瀏覽代碼

📦编写村史入口与列表对应,修改为查看列表

快乐的梦鱼 1 月之前
父節點
當前提交
36ad895a2d

+ 20 - 1
src/api/light/LightVillageApi.ts

@@ -9,6 +9,16 @@ export class VillageListItem extends DataModel<VillageListItem> {
     this._convertTable = {
       id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
       isLight: { clientSide: 'boolean' },
+      rank: { clientSide: 'number', serverSide: 'number' },
+      volunteerCount: { clientSide: 'number', serverSide: 'number' },
+      followCount: { clientSide: 'number', serverSide: 'number' },
+      collectCount: { clientSide: 'number', serverSide: 'number' },
+      light: { clientSide: 'number', serverSide: 'number' },
+      lightTotal: { clientSide: 'number', serverSide: 'number' },
+      fruitOutput: { clientSide: 'number', serverSide: 'number' },
+      fruitRemain: { clientSide: 'number', serverSide: 'number' },
+      fruitToday: { clientSide: 'number', serverSide: 'number' },
+      level: { clientSide: 'number', serverSide: 'number' },
     }
     this._convertKeyType = (key, direction) => {
       if (key.endsWith('At'))
@@ -53,7 +63,16 @@ export class VillageListItem extends DataModel<VillageListItem> {
   thumbnail = '';
   images = [] as string[];
   name = '';
-  title = '';
+  title = '';rank = 0;
+  volunteerCount = 0;
+  followCount = 0;
+  collectCount = 0;
+  light = 0;
+  lightTotal = 0;
+  fruitOutput = 0;
+  fruitRemain = 0;
+  fruitToday = 0;
+  level = 0;
   volunteerName = '';
 }
 

+ 26 - 2
src/common/composeabe/UserTools.ts

@@ -1,4 +1,5 @@
 import VillageApi, { VolunteerInfo } from "@/api/inhert/VillageApi";
+import { useSimpleDataLoader } from "@/components/composeabe/loader/SimpleDataLoader";
 import { useAuthStore } from "@/store/auth";
 import { ref } from "vue";
 
@@ -8,11 +9,9 @@ export function useUserTools() {
   const volunteerInfo = ref<VolunteerInfo | null>(null);
 
   async function getIsVolunteer() {
-
     if (!authStore.isLogged) {
       return false;
     }
-
     try {
       const volunteerInfo = await VillageApi.getVolunteerInfo();
       volunteerInfo.value = volunteerInfo;
@@ -21,9 +20,34 @@ export function useUserTools() {
       return false;
     }
   }
+  
+  const joinedVillagesLoader = useSimpleDataLoader(async () => {
+    try {
+      return await VillageApi.getClaimedVallageList();
+    } catch (error) {
+      return [];
+    }
+  });
+
+  async function getIsJoinedVillage(villageId: number) {
+    if (!authStore.isLogged) {
+      return false;
+    }
+    if (!joinedVillagesLoader.isLoaded.value) {
+      await joinedVillagesLoader.load();
+    }
+    try {
+      const isJoined = joinedVillagesLoader.content.value?.some(p => p.villageId === villageId) ?? false;
+      return isJoined;
+    } catch (error) {
+      return false;
+    }
+  }
 
   return {
     getIsVolunteer,
+    getIsJoinedVillage,
+    joinedVillagesLoader,
     volunteerInfo,
   };
 }

+ 2 - 1
src/components/composeabe/loader/LoaderCommon.ts

@@ -1,4 +1,4 @@
-import type { Ref } from "vue";
+import type { ComputedRef, Ref } from "vue";
 
 export type LoaderLoadType = 'loading' | 'finished' | 'nomore' | 'error' | 'empty';
 
@@ -10,6 +10,7 @@ export type LoaderLoadType = 'loading' | 'finished' | 'nomore' | 'error' | 'empt
 export interface ILoaderCommon<P> {
   error: Ref<string>;
   status: Ref<LoaderLoadType>;
+  isLoaded: ComputedRef<boolean>;
   load: (refresh?: boolean, params?: P) => Promise<void>;
   reload: () => Promise<void>;
 }

+ 6 - 1
src/components/composeabe/loader/SimpleDataLoader.ts

@@ -1,4 +1,4 @@
-import { onMounted, ref, type Ref } from "vue";
+import { computed, onMounted, ref, type Ref } from "vue";
 import type { ILoaderCommon, LoaderLoadType } from "./LoaderCommon";
 
 export interface ISimpleDataLoader<T, P> extends ILoaderCommon<P> {
@@ -62,10 +62,15 @@ export function useSimpleDataLoader<T, P = any>(
     }
   })
 
+  const isLoaded = computed(() => {
+    return status.value === 'finished' || status.value === 'nomore';
+  });
+
   return {
     content,
     status,
     error,
+    isLoaded,
     load,
     reload: () => load(true),
     getLastParams: () => lastParams,

+ 6 - 1
src/components/composeabe/loader/SimplePageListLoader.ts

@@ -1,5 +1,5 @@
 import { onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
-import { onMounted, ref, type Ref } from "vue";
+import { computed, onMounted, ref, type Ref } from "vue";
 import type { ILoaderCommon, LoaderLoadType } from "./LoaderCommon";
 
 export interface ISimplePageListLoader<T, P> extends ILoaderCommon<P> {
@@ -83,6 +83,10 @@ export function useSimplePageListLoader<T, P = any>(
       load(false, lastParams);
   })
 
+  const isLoaded = computed(() => {
+    return status.value === 'finished' || status.value === 'nomore';
+  });
+
   return {
     list,
     total,
@@ -91,5 +95,6 @@ export function useSimplePageListLoader<T, P = any>(
     error,
     load,
     reload: () => load(true),
+    isLoaded,
   }
 }

+ 0 - 13
src/pages.json

@@ -178,19 +178,6 @@
   ],
   "subPackages": [
     {
-      "root": "pages/home/post",
-      "pages": [
-        {
-          "path": "detail",
-          "style": {
-            "navigationBarTitleText": "微信贴图详情",
-            "navigationStyle": "custom",
-            "enablePullDownRefresh": false
-          }
-        }
-      ]
-    },
-    {
       "root": "pages/chat",
       "pages": [
         {

+ 5 - 5
src/pages/dig/details.vue

@@ -1,5 +1,5 @@
 <template>
-  <FlexCol v-if="volunteerInfo" :padding="30" :gap="20">
+  <FlexCol v-if="isJoined" :padding="30" :gap="20">
     <Image
       src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_1.jpg" 
       mode="widthFix"
@@ -53,7 +53,6 @@
   </FlexCol>
   <FlexCol v-else padding="padding.md">
     <FlexCol 
-      v-if="!volunteerInfo" 
       center 
       gap="gap.lg" 
       border="primary" 
@@ -83,7 +82,7 @@ import { useAuthStore } from '@/store/auth';
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from './forms/composeable/TaskEntryForm';
 import { useUserTools } from '@/common/composeabe/UserTools';
-import { onMounted } from 'vue';
+import { onMounted, ref } from 'vue';
 import { back, navTo } from '@/components/utils/PageAction';
 import Icon from '@/components/basic/Icon.vue';
 import Text from '@/components/basic/Text.vue';
@@ -109,8 +108,9 @@ const { querys } = useLoadQuerys({
 
 const authStore = useAuthStore();
 const { canCollect, isEmpty } = useCollectStore();
-const { getIsVolunteer, volunteerInfo } = useUserTools();
+const { getIsJoinedVillage } = useUserTools();
 const { goForm } = useTaskEntryForm();
+const isJoined = ref(false);
 
 function goCollect() {
   /* if (!canCollect('collect')) {
@@ -130,6 +130,6 @@ function goJoin() {
   });
 }
 onMounted(async () => {
-  await getIsVolunteer();
+  isJoined.value = await getIsJoinedVillage(querys.value.villageId);
 });
 </script>

+ 33 - 20
src/pages/dig/forms/list.vue

@@ -14,7 +14,7 @@
         <Button v-if="!querys.isView" type="primary" @click="newData">+ 编写</Button>
       </FlexRow>
       <FlexCol 
-        v-if="!volunteerInfo" 
+        v-if="!isJoined" 
         center 
         gap="gap.lg" 
         border="primary" 
@@ -44,7 +44,7 @@
           backgroundColor="white"
           direction="row"
           touchable
-          @click="goDetail(item.id)"
+          @click="goDetail(item)"
         >
           <Image 
             :src="item.image"
@@ -105,7 +105,8 @@ import Result from '@/components/feedback/Result.vue';
 const subTitle = ref('');
 const searchText = ref('');
 const collectStore = useCollectStore();
-const { getIsVolunteer, volunteerInfo } = useUserTools();
+const { getIsVolunteer, getIsJoinedVillage, volunteerInfo } = useUserTools();
+const isJoined = ref(false);
 const authStore = useAuthStore();
 const error = ref('');
 
@@ -113,7 +114,8 @@ const listLoader = useSimplePageListLoader<{
   id: number,
   image: string,
   title: string,
-  desc: string
+  desc: string,
+  villageVolunteerId: number,
 }, {
   villageId: number,  
   villageVolunteerId: number,
@@ -145,6 +147,7 @@ const listLoader = useSimplePageListLoader<{
       id: item.id,
       image: item.image,
       title: item.title,
+      villageVolunteerId: item.villageVolunteerId,
       desc: DataDateUtils.formatDate(item.updatedAt, 'YYYY-MM-dd') + (
         authStore.isAdmin ? (' 投稿人:' + item.villageVolunteerName) : ''
       )
@@ -157,11 +160,11 @@ const listLoader = useSimplePageListLoader<{
 }, false);
 
 function newData() {
-  if (!volunteerInfo.value) {
+  if (!isJoined.value) {
     confirm({ 
       title: '提示', 
       content: "您还不是当前村社的志愿者,请先加入志愿者队伍", 
-      confirmText: '去点亮村落',
+      confirmText: '去点亮',
     }).then((res) => {
       if (res) {
         goJoin();
@@ -182,18 +185,28 @@ function newData() {
     subId: querys.value.subId,  
   });
 }
-function goDetail(id: number) {
-  navTo('common', { 
-    id,
-    villageId: querys.value.villageId,
-    villageVolunteerId: querys.value.villageVolunteerId,
-    catalogId: querys.value.catalogId,
-    subType: querys.value.subType,
-    subKey: querys.value.subKey,
-    subId: querys.value.subId,
-    subTitle: querys.value.subTitle,
-    isView: querys.value.isView,
-  });
+function goDetail(item: { id: number, villageVolunteerId: number }) {
+  if (!authStore.isAdmin 
+    && (!isJoined.value || item.villageVolunteerId !== volunteerInfo.value?.id)
+  ) {
+    //非当前村社志愿者或者不是自己提交的文章,只能查看详情
+    navTo('/pages/home/discover/details', {
+      villageId: querys.value.villageId,
+      id: item.id,
+    });
+  } else {
+    navTo('common', { 
+      id: item.id,
+      villageId: querys.value.villageId,
+      villageVolunteerId: querys.value.villageVolunteerId,
+      catalogId: querys.value.catalogId,
+      subType: querys.value.subType,
+      subKey: querys.value.subKey,
+      subId: querys.value.subId,
+      subTitle: querys.value.subTitle,
+      isView: querys.value.isView,
+    });
+  }
 }
 function search() {
   listLoader.reload();
@@ -216,11 +229,11 @@ const { querys } = useLoadQuerys({
   subTitle: '',
   isView: false,
 }, async (querys) => {
+  isJoined.value = await getIsJoinedVillage(querys.villageId);
 
   if (querys.taskName) {
     //普通用户进入预览模式
     await getIsVolunteer();
-
     const menuDef = TaskMenuDef[querys.taskName];
     if (!menuDef) {
       error.value = '任务不存在';
@@ -229,7 +242,7 @@ const { querys } = useLoadQuerys({
     let catalog : TaskMenuDefItem | undefined ;
     if (querys.taskFindCatalogName) {
       querys.subTitle = querys.taskFindCatalogName;
-      catalog = menuDef.list.find((p) => p.name === querys.taskFindCatalogName);
+      catalog = menuDef.list.find((p) => p.title === querys.taskFindCatalogName);
     } else {
       catalog = menuDef.list[0];
     }

+ 12 - 0
src/pages/dig/forms/tasks.ts

@@ -381,4 +381,16 @@ export const TaskMenuDef : Record<string, TaskMenuDefGroup> = {
       },
     ],
   },
+  'ich': {
+    banner: 'https://mn.wenlvti.net/app_static/xiangan/banner_dig_trip.jpg',
+    list: [
+      {
+        title: '非遗展示',
+        desc: '',
+        icon: 'icon-task-trip-3',
+        enable: 'ich',
+        goForm: [ 'ich', 0, undefined, undefined, '非物质文化遗产项目', undefined ],
+      },
+    ],
+  },
 }

+ 11 - 0
src/pages/home/composeabe/OfficialAccount.ts

@@ -0,0 +1,11 @@
+export function useOfficialAccount() {
+
+
+  function onPublishSuccess(res: any) {
+    console.log(res);
+  }
+
+  return {
+    onPublishSuccess,
+  };
+}

+ 9 - 21
src/pages/home/index.vue

@@ -139,26 +139,12 @@
     })" />
     <VillageUserRankList :list="villageUserRankListLoader.content.value ?? []" />
 
-    <HomeTitle title="精选记忆" showMore />
-    <SimplePageListLoader :loader="recommendLoader">
-      <MasonryGrid>
-        <MasonryGridItem
-          v-for="(item, i) in recommendLoader.list.value"
-          :key="i"
-          :width="340"
-        >
-          <IndexCommonImageItem
-            :image="item.image"
-            :title="item.title"
-            :desc="item.content ?? ''"
-            :userName="item.nickName ?? ''"
-            :likes="item.likeCount"
-            :isLike="false"
-            @click="goMessageDetails(item)"
-          />
-        </MasonryGridItem>
-      </MasonryGrid>
-    </SimplePageListLoader>
+    <HomeTitle title="精选记忆" />
+    <official-account-publish
+      topic="亮乡源" 
+      @publishsuccess="onPublishSuccess"
+    >
+    </official-account-publish>
 
     <Height :height="150" />
 
@@ -224,9 +210,10 @@ import Text from '@/components/basic/Text.vue';
 import BackgroundBox from '@/components/display/block/BackgroundBox.vue';
 import Construction from '@/common/components/Construction.vue';
 import Width from '@/components/layout/space/Width.vue';
+import { useOfficialAccount } from './composeabe/OfficialAccount';
 
 const emit = defineEmits(['goVillage']);
-
+const { onPublishSuccess } = useOfficialAccount();
 const authStore = useAuthStore();
 const villageStore = useVillageStore();
 const themeContext = useTheme();
@@ -235,6 +222,7 @@ const searchKeywords = ref('');
 const showCityPopup = ref(false);
 const showMyFollowPopup = ref(false);
 
+
 const currentRegion = ref<number | null>(null);
 const { value: currentCity } = useStorageVar('currentCityName', '');
 const currentLocation = useGetCurrentLocation({

+ 0 - 113
src/pages/home/post/detail.vue

@@ -1,113 +0,0 @@
-<template>
-  <FlexCol :innerStyle="{
-    backgroundImage: 'url(https://xy.wenlvti.net/app_static/images/mine/TopBanner.png)',
-    backgroundSize: '100% auto',
-    backgroundRepeat: 'no-repeat',
-    backgroundPosition: 'top center',
-    minHeight: '100vh',
-  }">
-    <StatusBarSpace />
-    <NavBar :title="contentLoader.content.value?.title" leftButton="back" />
-    <SimplePageContentLoader :loader="contentLoader">
-      <template v-if="contentLoader.content.value">
-        <ImageSwiper :images="contentLoader.content.value.images" />
-        <FlexCol gap="gap.md" padding="space.md">
-          <H2>{{ contentLoader.content.value.title }}</H2>
-          <FlexRow align="center">
-            <Text :text="contentLoader.content.value.nickName" />
-          </FlexRow>
-          <Parse :content="contentLoader.content.value.content || ''" />
-        </FlexCol>
-      </template>
-    </SimplePageContentLoader>
-    <FlexCol
-      v-if="contentLoader.content.value" 
-      position="fixed" 
-      :inset="{ r: 0, b: 0, l: 0 }" 
-    >
-      <FlexRow
-        padding="space.md" 
-        justify="space-between"
-      >
-        <FlexRow align="center" gap="gap.md">
-          <Avatar
-            :image="contentLoader.content.value.avatar"
-            :size="40"
-          />
-          <Text :text="contentLoader.content.value.nickName" fontConfig="contentText" />
-        </FlexRow>
-        <FlexRow align="center" gap="gap.md">
-          <IconButton 
-            icon="favorite"
-            :text="contentLoader.content.value.likeCount.toString()"
-            @click="handleLike"
-          />
-          <button class="remove-button-style" open-type="share">
-            <IconButton 
-              icon="share"
-              :text="contentLoader.content.value.shareCount.toString()"
-              @click="handleShare"
-            />
-          </button>
-        </FlexRow>
-      </FlexRow>
-      <XBarSpace />
-    </FlexCol>
-  </FlexCol>
-</template>
-
-<script setup lang="ts">
-import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
-import { useLoadQuerys } from '@/components/composeabe/LoadQuerys';
-import FlexCol from '@/components/layout/FlexCol.vue';
-import LightVillageApi from '@/api/light/LightVillageApi';
-import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
-import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
-import Parse from '@/components/display/parse/Parse.vue';
-import H2 from '@/components/typography/H2.vue';
-import Text from '@/components/basic/Text.vue';
-import StatusBarSpace from '@/components/layout/space/StatusBarSpace.vue';
-import NavBar from '@/components/nav/NavBar.vue';
-import FlexRow from '@/components/layout/FlexRow.vue';
-import IconButton from '@/components/basic/IconButton.vue';
-import { toast } from '@/components/utils/DialogAction';
-import Avatar from '@/components/display/Avatar.vue';
-import XBarSpace from '@/components/layout/space/XBarSpace.vue';
-import { onShareTimeline, onShareAppMessage } from '@dcloudio/uni-app';
-
-const { querys } = useLoadQuerys({ 
-  id: 0,
-}, () => contentLoader.reload());
-
-const contentLoader = useSimpleDataLoader(async () => {
-  const res = await LightVillageApi.getMessageDetails(querys.value.id);
-  uni.setNavigationBarTitle({ title: res.title });
-  return res;
-}, false);
-
-async function handleLike() {
-  toast('TODO!');
-}
-async function handleShare() {
-  uni.share({
-    title: contentLoader.content.value?.title,
-    imageUrl: contentLoader.content.value?.images[0],
-    path: `/pages/home/post/detail?id=${querys.value.id}`,
-  });
-}
-
-onShareTimeline(() => {
-  return {
-    title: contentLoader.content.value?.title,
-    imageUrl: contentLoader.content.value?.images[0],
-    path: `/pages/home/post/detail?id=${querys.value.id}`,
-  };
-});
-onShareAppMessage(() => {
-  return {
-    title: contentLoader.content.value?.title,
-    imageUrl: contentLoader.content.value?.images[0],
-    path: `/pages/home/post/detail?id=${querys.value.id}`,
-  };
-});
-</script>

+ 1 - 1
src/pages/home/village/index.vue

@@ -31,7 +31,7 @@
             </template>
           </HomeLargeTitle>
         </FlexRow>
-        <Card v-if="tab === 'card'" />
+        <Card v-if="tab === 'card'" @goTree="tab = 'tree'" />
         <Tree v-if="tab === 'tree'" />
       </template>
       <Popup 

+ 66 - 100
src/pages/home/village/introd/card.vue

@@ -106,46 +106,44 @@
         }" 
       />
 
-      <Construction text="没有接口,数据不正确">
-        <FlexRow justify="space-between" align="center">
-          <FlexRow center gap="gap.lg" flexBasis="50%">
-            <Text text="村社排名" fontConfig="contentText" />
-            <Text text="No." fontConfig="lightTitle" />
-            <Text :text="villageInfoLoader.content.value?.rankText" fontConfig="primaryTitle" />
-          </FlexRow>
-          <FlexRow center gap="gap.lg" flexBasis="50%">
-            <Text text="村社等级" fontConfig="contentText" />
-            <Text :text="villageInfoLoader.content.value?.levelText" fontConfig="primaryTitle" />
-          </FlexRow>
+      <FlexRow justify="space-between" align="center">
+        <FlexRow center gap="gap.lg" flexBasis="50%">
+          <Text text="村社排名" fontConfig="contentText" />
+          <Text text="No." fontConfig="lightTitle" />
+          <Text :text="villageInfoLoader.content.value?.rankText" fontConfig="primaryTitle" />
         </FlexRow>
-
-        <FlexRow backgroundColor="background.tertiary" radius="radius.md" :padding="[30, 20]">
-          <FlexCol center gap="gap.sm" flexBasis="25%">
-            <Text text="乡源光" fontConfig="secondText" />
-            <Text :text="villageInfoLoader.content.value?.light" fontConfig="importantTitle" />
-          </FlexCol>
-          <Divider type="vertical" />
-          <FlexCol center gap="gap.sm" flexBasis="25%">
-            <Text text="乡源人数" fontConfig="contentText" />
-            <Text :text="villageInfoLoader.content.value?.memberCount" fontConfig="importantTitle" />
-          </FlexCol>
-          <Divider type="vertical" />
-          <FlexCol center gap="gap.sm" flexBasis="25%">
-            <Text text="关注人数" fontConfig="contentText" />
-            <Text :text="villageInfoLoader.content.value?.followerCount" fontConfig="importantTitle" />
-          </FlexCol>
-          <Divider type="vertical" />
-          <Button 
-            :padding="0" 
-            type="text" 
-            size="small" 
-            textColor="text.title"
-            text="新手上路" 
-            rightIcon="arrow-right" 
-            @click="handleGoNew()"
-          />
+        <FlexRow center gap="gap.lg" flexBasis="50%">
+          <Text text="村社等级" fontConfig="contentText" />
+          <Text :text="villageInfoLoader.content.value?.levelText" fontConfig="primaryTitle" />
         </FlexRow>
-      </Construction>
+      </FlexRow>
+
+      <FlexRow backgroundColor="background.tertiary" radius="radius.md" :padding="[30, 20]">
+        <FlexCol center gap="gap.sm" flexBasis="25%">
+          <Text text="乡源光" fontConfig="secondText" />
+          <Text :text="villageInfoLoader.content.value?.light" fontConfig="importantTitle" />
+        </FlexCol>
+        <Divider type="vertical" />
+        <FlexCol center gap="gap.sm" flexBasis="25%">
+          <Text text="乡源人数" fontConfig="contentText" />
+          <Text :text="villageInfoLoader.content.value?.memberCount" fontConfig="importantTitle" />
+        </FlexCol>
+        <Divider type="vertical" />
+        <FlexCol center gap="gap.sm" flexBasis="25%">
+          <Text text="关注人数" fontConfig="contentText" />
+          <Text :text="villageInfoLoader.content.value?.followerCount" fontConfig="importantTitle" />
+        </FlexCol>
+        <Divider type="vertical" />
+        <Button 
+          :padding="0" 
+          type="text" 
+          size="small" 
+          textColor="text.title"
+          text="新手上路" 
+          rightIcon="arrow-right" 
+          @click="handleGoNew()"
+        />
+      </FlexRow>
     </BackgroundBox>
 
     <!-- 排行榜 -->
@@ -185,14 +183,14 @@
       GridItemPaddingVertical: 8,
     }">
       <Grid :borderGrid="false" :mainAxisCount="4">
-        <GridItem title="村概况" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeIntrod.png" touchable @click="handleGoCollect('overview')" />
-        <GridItem title="自然风光" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeEnvirounment.png" touchable @click="handleGoCollect('environment')" />
-        <GridItem title="历史沿革" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeHistory.png" touchable @click="handleGoCollect('history')" />
+        <GridItem title="村概况" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeIntrod.png" touchable @click="handleGoCollect('overview')" />
+        <GridItem title="自然风光" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeEnvirounment.png" touchable @click="handleGoCollect('environment', '自然环境')" />
+        <GridItem title="历史沿革" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeHistory.png" touchable @click="handleGoCollect('history', '建村历史')" />
         <GridItem title="特色产业" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeIndustry.png" touchable @click="handleGoCollect('product')"    />
-        <GridItem title="文艺活动" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeActivity.png" touchable @click="handleGoCollect('trip')" />
+        <GridItem title="文艺活动" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeActivity.png" touchable @click="handleGoCollect('custom')" />
         <GridItem title="非遗展示" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeShow.png" touchable @click="handleGoCollect('ich')" />
         <GridItem title="民俗风采" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeFolkloreVibe.png" touchable @click="handleGoCollect('custom')" />
-        <GridItem title="乡贤故事" icon="https://xy.wenlvti.net/app_static/images/village/IconGoods.png" touchable @click="toast('TODO')" />
+        <GridItem title="乡贤故事" icon="https://xy.wenlvti.net/app_static/images/village/IconGoods.png" touchable @click="handleGoCollect('history', '历史人物')" />
       </Grid>
     </ProvideVar>
 
@@ -207,7 +205,7 @@
       <Grid :borderGrid="false" :mainAxisCount="4">
         <GridItem title="乡源荣光" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeHornor.png" touchable />
         <GridItem title="乡源好物" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeGoods.png" touchable />
-        <GridItem title="乡源树" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeTree.png" touchable />
+        <GridItem title="乡源树" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeTree.png" touchable @click="emit('goTree')" />
         <GridItem title="政贤连心" icon="https://xy.wenlvti.net/app_static/images/village/IconGovAffairs.png" touchable />
         <GridItem title="互动游戏" icon="https://xy.wenlvti.net/app_static/images/village/IconLargeGame.png" touchable />
       </Grid>
@@ -233,25 +231,11 @@
       </template>
     </HomeTitle>
     <RoundTags v-model:active="listActiveTag" :tags="['广场', '老味道', '老手艺', '老物件', '老故事']" />
-    <SimplePageListLoader :loader="recommendLoader">
-      <MasonryGrid>
-        <MasonryGridItem
-          v-for="(item, i) in recommendLoader.list.value"
-          :key="i"
-          :width="340"
-        >
-          <IndexCommonImageItem
-            :image="item.image"
-            :title="item.title"
-            :desc="item.content ?? ''"
-            :userName="item.nickName ?? ''"
-            :likes="item.likeCount"
-            :isLike="false"
-            @click="handleGoPost(item.id)"
-          />
-        </MasonryGridItem>
-      </MasonryGrid>
-    </SimplePageListLoader>
+    <official-account-publish
+      :topic="recommendTagName" 
+      @publishsuccess="onPublishSuccess"
+    >
+    </official-account-publish>
 
   </FlexCol>
 
@@ -259,7 +243,8 @@
 
 <script setup lang="ts">
 import { computed, ref, watch } from 'vue';
-import { useSimplePageListLoader } from '@/components/composeabe/loader/SimplePageListLoader';
+import { useUserTools } from '@/common/composeabe/UserTools';
+import { useOfficialAccount } from '../../composeabe/OfficialAccount';
 import { useAuthStore } from '@/store/auth';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
 import { useVillageStore } from '@/store/village';
@@ -285,41 +270,42 @@ import BackgroundImageButton from '@/components/basic/BackgroundImageButton.vue'
 import ProvideVar from '@/components/theme/ProvideVar.vue';
 import Grid from '@/components/layout/grid/Grid.vue';
 import GridItem from '@/components/layout/grid/GridItem.vue';
-import MasonryGrid from '@/components/layout/masonry/MasonryGrid.vue';
-import MasonryGridItem from '@/components/layout/masonry/MasonryGridItem.vue';
-import IndexCommonImageItem from '@/common/components/parts/IndexCommonImageItem.vue';
-import FollowVillageApi from '@/api/light/FollowVillageApi';
 import LightVillageApi from '@/api/light/LightVillageApi';
-import SimplePageListLoader from '@/components/loader/SimplePageListLoader.vue';
 import Construction from '@/common/components/Construction.vue';
-import VillageApi from '@/api/inhert/VillageApi';
-import { useUserTools } from '@/common/composeabe/UserTools';
 
 const authStore = useAuthStore();
 const { getIsVolunteer } = useUserTools();
 const { requireLogin } = useReqireLogin();
-const villageStore = useVillageStore();
+const { onPublishSuccess } = useOfficialAccount();
 const { isFollowed, onFollow, onUnFollow } = useFollow();
+const villageStore = useVillageStore();
+const { getIsJoinedVillage } = useUserTools();
+const isJoined = ref(false);
 const villageInfoLoader = useSimpleDataLoader(async () => {
   const village = villageStore.currentVillage;  
-  console.log(village);
+  if (village) 
+    isJoined.value = await getIsJoinedVillage(village.id);
   return {
     title: village?.name || '',
     desc: village?.desc || '',
     address: village?.address,
     applyCount: village?.applyCount || 0,
     sizeText: village?.sizeText || 0,
-    levelText: village?.levelText as string || '',
-    rankText: village?.rankText as string || '',
+    levelText: village?.level.toString() || '',
+    rankText: village?.rank.toString() || '',
     light: village?.light as number || 0,
-    memberCount: village?.memberCount as number || 0,
-    followerCount: village?.followerCount as number || 0,
+    memberCount: village?.volunteerCount as number || 0,
+    followerCount: village?.followCount as number || 0,
     images: village?.images || [],
     longitude: village?.longitude as number || 0,
     latitude: village?.latitude as number || 0,
   };
 });
 
+const emit = defineEmits<{
+  (e: 'goTree'): void;
+}>();
+
 const rankActiveTag = ref('乡源果');
 const listActiveTag = ref('广场');
 
@@ -348,29 +334,10 @@ watch(rankActiveTag, () => {
   villageUserRankListLoader.reload();
 });
 
-const meIsVolunteer = ref(false);
-const myJoinedVillagesLoader = useSimpleDataLoader(async () => {
-  try {
-    meIsVolunteer.value = await getIsVolunteer();
-    if (!meIsVolunteer.value) 
-      return [];
-    return await VillageApi.getClaimedVallageList();
-  } catch (error) {
-    return [];
-  }
-});
-const isJoined = computed(() => {
-  return myJoinedVillagesLoader.content.value?.some(p => p.id === villageStore.currentVillage?.id) ?? false;
-});
 
-const recommendLoader = useSimplePageListLoader(20, async (page, pageSize) => {
-  return await LightVillageApi.getMessages(page, pageSize, {
-    villageId: villageStore.currentVillage?.id ?? undefined,
-    keywords: listActiveTag.value,
-  });
-});
-watch(listActiveTag, () => {
-  recommendLoader.reload();
+
+const recommendTagName = computed(() => {
+  return '亮乡源·' + villageInfoLoader.content.value?.title + '·' + listActiveTag.value;
 });
 
 function handleGoJoin() {
@@ -425,7 +392,6 @@ function handleGoPost(id: number) {
 
 watch(() => villageStore.currentVillage, () => {
   villageInfoLoader.reload();
-  recommendLoader.reload();
   villageUserRankListLoader.reload();
 }, { immediate: true });
 </script>