快乐的梦鱼 1 месяц назад
Родитель
Сommit
0b39b760c8

+ 1 - 0
src/common/components/CommonDialog.vue

@@ -5,6 +5,7 @@
     closeable
     closeable
     closeIcon=""
     closeIcon=""
     backgroundColor="transparent"
     backgroundColor="transparent"
+    contentScrollMaxHeight="80vh"
     @update:show="emit('update:show', $event)"
     @update:show="emit('update:show', $event)"
   >
   >
     <BackgroundBox 
     <BackgroundBox 

+ 1 - 1
src/common/composeabe/RequireLogin.ts

@@ -6,7 +6,7 @@ import { useAuthStore } from "@/store/auth";
  * 说明:
  * 说明:
  * * 登录校验组合式代码。
  * * 登录校验组合式代码。
  */
  */
-export function useReqireLogin() {
+export function useRequireLogin() {
   const authStore = useAuthStore();
   const authStore = useAuthStore();
  
  
   return {
   return {

+ 2 - 0
src/components/canvas/MiniRender.ts

@@ -66,6 +66,8 @@ export namespace MiniRender {
 
 
     public parent: Container | null = null;
     public parent: Container | null = null;
 
 
+    public data: any = null;
+
     private listeners = new Map<RenderObjectEventName, Set<RenderObjectEventHandler>>();
     private listeners = new Map<RenderObjectEventName, Set<RenderObjectEventHandler>>();
 
 
     constructor(id?: RenderObjectId) {
     constructor(id?: RenderObjectId) {

+ 1 - 1
src/pages/home/components/LightMap.vue

@@ -293,7 +293,7 @@ onMounted(async () => {
       clear: false,
       clear: false,
     });
     });
   });
   });
-  //await regionLoader.reload();
+  await regionLoader.reload();
 });
 });
 </script>
 </script>
 
 

+ 2 - 2
src/pages/home/index.vue

@@ -183,7 +183,7 @@ import { useStorageVar } from '@/components/composeabe/StorageVar';
 import { useVillageStore } from '@/store/village';
 import { useVillageStore } from '@/store/village';
 import { useGetCurrentLocation } from './composeabe/GetCurrentLocation';
 import { useGetCurrentLocation } from './composeabe/GetCurrentLocation';
 import { useAuthStore } from '@/store/auth';
 import { useAuthStore } from '@/store/auth';
-import { useReqireLogin } from '@/common/composeabe/RequireLogin';
+import { useRequireLogin } from '@/common/composeabe/RequireLogin';
 import { useOfficialAccount } from './composeabe/OfficialAccount';
 import { useOfficialAccount } from './composeabe/OfficialAccount';
 import { useUserTools } from '@/common/composeabe/UserTools';
 import { useUserTools } from '@/common/composeabe/UserTools';
 import { ArrayUtils, waitTimeOut } from '@imengyu/imengyu-utils';
 import { ArrayUtils, waitTimeOut } from '@imengyu/imengyu-utils';
@@ -217,7 +217,7 @@ const { onPublishSuccess } = useOfficialAccount();
 const authStore = useAuthStore();
 const authStore = useAuthStore();
 const villageStore = useVillageStore();
 const villageStore = useVillageStore();
 const themeContext = useTheme();
 const themeContext = useTheme();
-const { requireLogin } = useReqireLogin();
+const { requireLogin } = useRequireLogin();
 const { getIsVolunteer } = useUserTools();
 const { getIsVolunteer } = useUserTools();
 const searchKeywords = ref('');
 const searchKeywords = ref('');
 const showCityPopup = ref(false);
 const showCityPopup = ref(false);

+ 1 - 1
src/pages/home/village/bless/my-orders.vue

@@ -68,7 +68,7 @@ const listLoader = useSimplePageListLoader(10, async (page, pageSize) => {
   const res = await TreeApi.getBlessOrders({
   const res = await TreeApi.getBlessOrders({
     page,
     page,
     pageSize,
     pageSize,
-    villageId: querys.value.villageId,
+    villageId: querys.value.villageId || undefined,
     userId: authStore.userId,
     userId: authStore.userId,
   });
   });
   return {
   return {

+ 101 - 53
src/pages/home/village/components/VillageTree.vue

@@ -18,8 +18,16 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
 import { MiniRender } from '@/components/canvas/MiniRender';
 import { MiniRender } from '@/components/canvas/MiniRender';
 import { UniWeappRender } from '@/components/canvas/UniWeappRender';
 import { UniWeappRender } from '@/components/canvas/UniWeappRender';
+import { RandomUtils } from '@imengyu/imengyu-utils';
 import { getCurrentInstance, onBeforeUnmount, onMounted } from 'vue';
 import { getCurrentInstance, onBeforeUnmount, onMounted } from 'vue';
 
 
+let currentText : MiniRender.Text | null = null;
+const todoTreeText = '现在没有树的动画,树是静态的。';
+
+const emit = defineEmits<{
+  (e: 'fruitPick'): void;
+}>();
+
 const HEIGHT = 260;
 const HEIGHT = 260;
 const instance = getCurrentInstance();
 const instance = getCurrentInstance();
 const systemInfo = uni.getWindowInfo();
 const systemInfo = uni.getWindowInfo();
@@ -38,79 +46,118 @@ const render = new MiniRender.Scene(
     bg.width = systemInfo.windowWidth;
     bg.width = systemInfo.windowWidth;
     bg.height = HEIGHT;
     bg.height = HEIGHT;
 
 
-
-    const text = new MiniRender.Text('动画问题解决啦,就等设计师出图了!', {
+    const text = new MiniRender.Text(todoTreeText, {
       fontSize: 20,
       fontSize: 20,
       color: '#000',
       color: '#000',
       align: 'left',
       align: 'left',
       wrap: 'wrap',
       wrap: 'wrap',
-      maxWidth: 200,
+      maxWidth: 300,
     });
     });
     text.x = 70;
     text.x = 70;
     text.y = 50;
     text.y = 50;
+    currentText = text;
 
 
-    const robot = new MiniRender.AnimateSprite({
-      framerate: 7,
-      images: ['https://docs.imengyu.top/assets/character_robot_sheet.png'],
-      frames: [
-        // 来自 character_robot_sheet.xml(96x128)
-        // walk0..walk7
-        [0, 512, 96, 128],
-        [96, 512, 96, 128],
-        [192, 512, 96, 128],
-        [288, 512, 96, 128],
-        [384, 512, 96, 128],
-        [480, 512, 96, 128],
-        [576, 512, 96, 128],
-        [672, 512, 96, 128],
-        // run0..run2
-        [576, 256, 96, 128],
-        [672, 256, 96, 128],
-        [768, 256, 96, 128],
-        // attack0..attack2
-        [0, 384, 96, 128],
-        [96, 384, 96, 128],
-        [192, 384, 96, 128],
-      ],
-      animations: {
-        walk: { frames: [0, 1, 2, 3, 4, 5, 6, 7] },
-        run: { frames: [8, 9, 10] },
-        attack: { frames: [11, 12, 13], loop: false },
-      },
-      playOnce: false,
-      currentAnimation: 'walk',
-    });
-    robot.x = 30;
-    robot.y = 105;
-    robot.play();
-
-    const flag = new MiniRender.Sprite();
-    flag.src = 'https://xy.wenlvti.net/app_static/images/village/TreeTestFlag.png';
-    flag.x = 125;
-    flag.y = 144;
-    flag.width = 80;
-    flag.height = 100;
-    flag.interactive = true;
-    flag.on('click', () => {
-      uni.showToast({
-        title: 'flag clicked',
-        icon: 'success',
-      });
-    });
+    const treeMain = new MiniRender.Sprite();
+    treeMain.src = 'https://xy.wenlvti.net/app_static/images/home/tree/Level4.png';
+    treeMain.x = 135;
+    treeMain.y = 55;
+    treeMain.width = 180;
+    treeMain.height = 200;
+    treeMain.interactive = true;
 
 
     render.root
     render.root
       .add(bg)
       .add(bg)
       .add(text)
       .add(text)
-      .add(flag)
-      .add(robot);
+      .add(treeMain)
   },
   },
   (dtMs: number) => {
   (dtMs: number) => {
 
 
   }
   }
 );
 );
 
 
+function createFruit() {
+  const fruit = new MiniRender.AnimateSprite({
+    framerate: 7,
+    images: ['https://xy.wenlvti.net/app_static/images/home/tree/AnimFruit.png'],
+    frames: [
+      [0, 0, 30, 30],
+      [30, 0, 30, 30],
+      [60, 0, 30, 30],
+      [90, 0, 30, 30],
+      [120, 0, 30, 30],
+      [150, 0, 30, 30],
+    ],
+    animations: {
+      default: { frames: [0, 1, 2, 3, 4, 5] },
+    },
+    playOnce: false,
+    currentAnimation: 'walk',
+  });
+  fruit.play();
+  fruit.x = RandomUtils.genRandom(120, 260);
+  fruit.y = RandomUtils.genRandom(90, 120);
+  fruit.width = 30;
+  fruit.height = 30;
+  fruit.interactive = true;
+  fruit.data = {
+    type: 'fruit',
+  };
+  fruit.on('click', () => {
+    emit('fruitPick');
+  });
+  render.root.add(fruit);
+}
+
+function createFruits(count: number) {
+  //创建或者删除水果,使得数量等于count
+  const fruitNodes = render.root.children.filter((child) => child.data?.type === 'fruit');
+  const fruits = fruitNodes.length;
+  if (fruits === count) {
+    return;
+  }
+  if (fruits > count) {
+    fruitNodes.slice(0, fruits - count).forEach((fruit) => {
+      render.root.remove(fruit);
+    });
+    return;
+  }
+  for (let i = 0; i < count - fruits; i++) {
+    createFruit();
+  }
+}
+
+function removeAllFruit() {
+  const fruits = render.root.children.filter(child => child.data?.type === 'fruit');
+  fruits.forEach(fruit => {
+    render.root.remove(fruit);
+  });
+}
+
 function playStateAnimation(state: 'collect' | 'water' | 'fertilize' | 'task' | 'bless' | 'exchange') {
 function playStateAnimation(state: 'collect' | 'water' | 'fertilize' | 'task' | 'bless' | 'exchange') {
   //TODO: 播放动画
   //TODO: 播放动画
+  if (currentText) {
+    switch (state) {
+      case 'collect':
+        currentText.text = '拾果状态' + todoTreeText;
+        removeAllFruit();
+        break;
+      case 'water':
+        currentText.text = '浇水状态' + todoTreeText;
+        break;
+      case 'fertilize':
+        currentText.text = '施肥状态' + todoTreeText;
+        break;
+      case 'task':
+        currentText.text = '任务状态' + todoTreeText;
+        break;
+      case 'bless':
+        currentText.text = '赐福状态' + todoTreeText;
+        break;
+      case 'exchange':
+        currentText.text = '兑换状态' + todoTreeText;
+        break;
+    }
+  }
 }
 }
 
 
 defineExpose({
 defineExpose({
@@ -118,6 +165,7 @@ defineExpose({
     render.root.removeAll();
     render.root.removeAll();
     render.init();
     render.init();
   },
   },
+  createFruits,
   playStateAnimation,
   playStateAnimation,
 });
 });
 
 

+ 2 - 2
src/pages/home/village/composeabe/Follow.ts

@@ -1,12 +1,12 @@
 import FollowVillageApi from "@/api/light/FollowVillageApi";
 import FollowVillageApi from "@/api/light/FollowVillageApi";
-import { useReqireLogin } from "@/common/composeabe/RequireLogin";
+import { useRequireLogin } from "@/common/composeabe/RequireLogin";
 import { useVillageStore } from "@/store/village";
 import { useVillageStore } from "@/store/village";
 import { computed } from "vue";
 import { computed } from "vue";
 import { toast, confirm } from "@/components/dialog/CommonRoot";
 import { toast, confirm } from "@/components/dialog/CommonRoot";
 
 
 export function useFollow() {
 export function useFollow() {
 
 
-  const { requireLogin } = useReqireLogin();
+  const { requireLogin } = useRequireLogin();
   const villageStore = useVillageStore();
   const villageStore = useVillageStore();
   const isFollowed = computed(() => {
   const isFollowed = computed(() => {
     return villageStore.myFollowVillages.some(p => p.id === villageStore.currentVillage?.id);
     return villageStore.myFollowVillages.some(p => p.id === villageStore.currentVillage?.id);

+ 30 - 35
src/pages/home/village/dialogs/ApplyGoodsDialog.vue

@@ -1,27 +1,43 @@
 <template>
 <template>
   <CommonDialog v-model:show="show" title="升级村社">
   <CommonDialog v-model:show="show" title="升级村社">
     <FlexCol gap="gap.lg">
     <FlexCol gap="gap.lg">
-      <FlexRow wrap justify="space-around" gap="gap.md">
-        <BackgroundBox 
-          v-for="(item, k) in infoGrids"
+      <FlexCol gap="gap.md">
+        <BackgroundBox
+          v-for="(item, k) in upgradeList"
           :key="k"
           :key="k"
+          position="relative"
           backgroundImage="https://xy.wenlvti.net/app_static/images/village/BoxMid.png"
           backgroundImage="https://xy.wenlvti.net/app_static/images/village/BoxMid.png"
           :backgroundCutBorder="32"
           :backgroundCutBorder="32"
           :backgroundCutBorderSize="36"
           :backgroundCutBorderSize="36"
-          :padding="24"
-          :innerStyle="{ width: 'calc(50% - 58rpx)' }"
-          direction="column"
+          :padding="32"
+          direction="row"
+          justify="space-between"
           align="center"
           align="center"
           gap="gap.md"
           gap="gap.md"
         >
         >
-          <Text :text="item.label" fontConfig="lightImportantTitle"  />
-          <Text :text="item.desc" fontConfig="lightGoldTitle" :fontSize="30" />
-          <FlexRow align="center" gap="gap.sm">
-            <Text :text="item.value" fontConfig="lightGoldTitle" :fontSize="50" />
-            <Text :text="item.unit" fontConfig="contentText" />
-          </FlexRow>
+          <FlexCol>
+            <FlexRow align="center" gap="gap.md">
+              <Text :text="item.name" fontConfig="lightImportantTitle" :fontSize="42" />
+              <FlexRow 
+                v-if="item.isRecommend"
+                radius="radius.md"
+                backgroundColor="danger"
+                :padding="[4, 12]"
+              >
+                <Text text="推荐升级" fontConfig="contentText" color="white" />
+              </FlexRow>
+            </FlexRow>
+            <Text :text="item.desc" fontConfig="lightGoldTitle" :fontSize="30" />
+          </FlexCol>
+          <FlexCol>
+            <Text :text="item.vipLevel + '级'" fontConfig="contentText" />
+            <FlexRow align="center">
+              <Text fontConfig="lightGoldTitle">¥</Text>
+              <Text :text="item.price" fontFamily="SongtiSCBlack" fontConfig="lightGoldTitle" fontSize="50" />
+            </FlexRow>
+          </FlexCol>
         </BackgroundBox>
         </BackgroundBox>
-      </FlexRow>
+      </FlexCol>
       <BackgroundBox 
       <BackgroundBox 
         backgroundImage="https://xy.wenlvti.net/app_static/images/village/BoxMid.png"
         backgroundImage="https://xy.wenlvti.net/app_static/images/village/BoxMid.png"
         :backgroundCutBorder="32"
         :backgroundCutBorder="32"
@@ -31,12 +47,8 @@
         center
         center
       >
       >
         <Text text="额外权益" fontConfig="lightImportantTitle" />
         <Text text="额外权益" fontConfig="lightImportantTitle" />
-        <Text text="TODO: 此处为测试数据,还未规定升级方案。平台首页展厅/阁楼名投、好图上传、村图券赠送、修改图片平台基础建设、花田引入正版授权歌曲+30%、乡源果奖励等" fontConfig="contentText" />
+        <Text text="平台首页展厅/好图上传、村图券赠送、修改图片等功能;平台基础建设、乡源光、乡源果奖励等" fontConfig="contentText" />
       </BackgroundBox>
       </BackgroundBox>
-      <FlexRow justify="space-around" gap="gap.md">
-        <FrameButton text="取消" @click="show = false" width="220rpx" />
-        <FrameButton primary text="去申请" @click="show = false" width="220rpx" />
-      </FlexRow>
     </FlexCol>
     </FlexCol>
   </CommonDialog>
   </CommonDialog>
 </template>
 </template>
@@ -61,23 +73,6 @@ const props = defineProps({
 
 
 const upgradeList = ref<UpgradePackageItem[]>([]);
 const upgradeList = ref<UpgradePackageItem[]>([]);
 
 
-const infoGrids = computed(() =>
-  upgradeList.value.map((item) => [
-    {
-      label: '认证等级',
-      desc: `${item.name}·年费`,
-      value: String(item.price),
-      unit: '元/年',
-    },
-    {
-      label: '管理员',
-      desc: '管理员上限',
-      value: String(item.managerLimit),
-      unit: '人',
-    },
-  ]).flat(),
-);
-
 async function loadUpgradeList() {
 async function loadUpgradeList() {
   const res = await TreeApi.getUpgradeList();
   const res = await TreeApi.getUpgradeList();
   upgradeList.value = res.list;
   upgradeList.value = res.list;

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

@@ -97,7 +97,7 @@ onMounted(() => {
     });
     });
   }
   }
   if (isDevEnv) {
   if (isDevEnv) {
-    tab.value = 'tree';
+    //tab.value = 'tree';
   }
   }
 });
 });
 
 

+ 2 - 2
src/pages/home/village/introd/card.vue

@@ -231,7 +231,7 @@ import { useOfficialAccount } from '../../composeabe/OfficialAccount';
 import { useAuthStore } from '@/store/auth';
 import { useAuthStore } from '@/store/auth';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
 import { useVillageStore } from '@/store/village';
 import { useVillageStore } from '@/store/village';
-import { useReqireLogin } from '@/common/composeabe/RequireLogin';
+import { useRequireLogin } from '@/common/composeabe/RequireLogin';
 import { useFollow } from '../composeabe/Follow';
 import { useFollow } from '../composeabe/Follow';
 import { confirm, toast } from '@/components/utils/DialogAction';
 import { confirm, toast } from '@/components/utils/DialogAction';
 import { ArrayUtils } from '@imengyu/imengyu-utils';
 import { ArrayUtils } from '@imengyu/imengyu-utils';
@@ -262,7 +262,7 @@ import VillageGallery from '../components/VillageGallery.vue';
 
 
 const authStore = useAuthStore();
 const authStore = useAuthStore();
 const { getIsVolunteer } = useUserTools();
 const { getIsVolunteer } = useUserTools();
-const { requireLogin } = useReqireLogin();
+const { requireLogin } = useRequireLogin();
 const { onPublishSuccess } = useOfficialAccount();
 const { onPublishSuccess } = useOfficialAccount();
 const { isFollowed, onFollow, onUnFollow } = useFollow();
 const { isFollowed, onFollow, onUnFollow } = useFollow();
 const villageStore = useVillageStore();
 const villageStore = useVillageStore();

+ 28 - 8
src/pages/home/village/introd/tree.vue

@@ -5,6 +5,7 @@
     </FlexCol>
     </FlexCol>
     <VillageTree 
     <VillageTree 
       ref="villageTreeRef"
       ref="villageTreeRef"
+      @fruitPick="handlePick"
     />
     />
     <FlexCol :padding="30">
     <FlexCol :padding="30">
       <FlexCol>
       <FlexCol>
@@ -57,10 +58,10 @@
       </FlexRow>
       </FlexRow>
 
 
       <HomeTitle title="最新动态" />
       <HomeTitle title="最新动态" />
-      <SimplePageContentLoader :loader="infoLoader" :emptyView="{ text: '冷冷清清,等你来添光加彩' }">
+      <SimplePageContentLoader :loader="activityLoader" :emptyView="{ text: '冷冷清清,等你来添光加彩' }">
         <FlexCol gap="gap.lg">
         <FlexCol gap="gap.lg">
           <FlexRow 
           <FlexRow 
-            v-for="item in infoLoader.content.value" :key="item.id"
+            v-for="item in activityLoader.content.value" :key="item.id"
             backgroundColor="background.tertiary"
             backgroundColor="background.tertiary"
             radius="radius.md"
             radius="radius.md"
             :padding="[20, 30]"
             :padding="[20, 30]"
@@ -134,12 +135,13 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { ref, watch } from 'vue';
+import { onBeforeMount, onMounted, ref, watch } from 'vue';
 import { useVillageStore } from '@/store/village';
 import { useVillageStore } from '@/store/village';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
-import { useReqireLogin } from '@/common/composeabe/RequireLogin';
+import { useRequireLogin } from '@/common/composeabe/RequireLogin';
 import { showError } from '@/common/composeabe/ErrorDisplay';
 import { showError } from '@/common/composeabe/ErrorDisplay';
 import { navTo } from '@/components/utils/PageAction';
 import { navTo } from '@/components/utils/PageAction';
+import { RequestApiError, SimpleTimer } from '@imengyu/imengyu-utils';
 import HomeTitle from '@/common/components/parts/HomeTitle.vue';
 import HomeTitle from '@/common/components/parts/HomeTitle.vue';
 import Text from '@/components/basic/Text.vue';
 import Text from '@/components/basic/Text.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
@@ -155,19 +157,18 @@ import Progress from '@/components/display/Progress.vue';
 import TreeApi, { type BlessPackageItem, type GrowthLogFeedItem } from '@/api/light/TreeApi';
 import TreeApi, { type BlessPackageItem, type GrowthLogFeedItem } from '@/api/light/TreeApi';
 import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
 import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
 import BlessBuyDialog from '../dialogs/BlessBuyDialog.vue';
 import BlessBuyDialog from '../dialogs/BlessBuyDialog.vue';
-import { RequestApiError } from '@imengyu/imengyu-utils';
 
 
 const GROWTH_FEED_COUNT = 6;
 const GROWTH_FEED_COUNT = 6;
 const DEFAULT_AVATAR = 'https://xy.wenlvti.net/app_static/images/village/PlaceholderVolunteer.png';
 const DEFAULT_AVATAR = 'https://xy.wenlvti.net/app_static/images/village/PlaceholderVolunteer.png';
 
 
 const villageStore = useVillageStore();
 const villageStore = useVillageStore();
-const { requireLoginAsync } = useReqireLogin();
+const { requireLoginAsync } = useRequireLogin();
 
 
 const blessBuyDialogRef = ref<InstanceType<typeof BlessBuyDialog>>();
 const blessBuyDialogRef = ref<InstanceType<typeof BlessBuyDialog>>();
 const villageTreeRef = ref<InstanceType<typeof VillageTree>>();
 const villageTreeRef = ref<InstanceType<typeof VillageTree>>();
 const currentBless = ref<BlessPackageItem>();
 const currentBless = ref<BlessPackageItem>();
 
 
-const infoLoader = useSimpleDataLoader(async () => {
+const activityLoader = useSimpleDataLoader(async () => {
   const villageId = villageStore.currentVillage?.id;
   const villageId = villageStore.currentVillage?.id;
   if (!villageId) return [];
   if (!villageId) return [];
 
 
@@ -219,7 +220,8 @@ const infoLoader = useSimpleDataLoader(async () => {
 });
 });
 
 
 watch(() => villageStore.currentVillage?.id, () => {
 watch(() => villageStore.currentVillage?.id, () => {
-  infoLoader.reload();
+  activityLoader.reload();
+  getFruits();
 });
 });
 const blessingInfoLoader = useSimpleDataLoader(async () => {
 const blessingInfoLoader = useSimpleDataLoader(async () => {
   const res = await TreeApi.getBlessList({ page: 1, pageSize: 18 });
   const res = await TreeApi.getBlessList({ page: 1, pageSize: 18 });
@@ -323,4 +325,22 @@ async function handlePickOrWaterOrFertilize(action: 'pick' | 'water' | 'fertiliz
     showError(e);
     showError(e);
   }
   }
 }
 }
+
+async function getFruits() {
+  if (!villageStore.currentVillage?.id) 
+    return;
+  const res = await TreeApi.dropFruit(villageStore.currentVillage.id);
+  if (res) {
+    villageTreeRef.value?.createFruits(res.fruitRemain);
+  }
+}
+
+const refreshFruitTimer = new SimpleTimer(undefined, () => getFruits(), 15000);
+
+onMounted(() => {
+  refreshFruitTimer.start();
+});
+onBeforeMount(() => {
+  refreshFruitTimer.stop();
+});
 </script>
 </script>

+ 3 - 1
src/pages/user/index.vue

@@ -47,7 +47,7 @@
         <Cell v-if="userInfo" icon="https://xy.wenlvti.net/app_static/images/mine/IconMyArticle.png" title="我的投稿" showArrow touchable @click="navTo('/pages/dig/forms/submits', { 
         <Cell v-if="userInfo" icon="https://xy.wenlvti.net/app_static/images/mine/IconMyArticle.png" title="我的投稿" showArrow touchable @click="navTo('/pages/dig/forms/submits', { 
           villageVolunteerId: volunteerInfoLoader.content.value?.id || 0 
           villageVolunteerId: volunteerInfoLoader.content.value?.id || 0 
         })" />
         })" />
-        <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconMyRecord.png" title="福泽记录" showArrow touchable />
+        <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconMyRecord.png" title="福泽记录" showArrow touchable @click="requireLogin(() => navTo('/pages/home/bless/my-orders'), '登录后查看我的福泽记录哦')" />
         <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconMyReward.png" title="兑换记录" showArrow touchable />
         <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconMyReward.png" title="兑换记录" showArrow touchable />
         <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconAbout.png" title="关于我们" showArrow touchable @click="navTo('/pages/home/about/about')" />
         <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconAbout.png" title="关于我们" showArrow touchable @click="navTo('/pages/home/about/about')" />
         <button open-type="contact" class="remove-button-style">
         <button open-type="contact" class="remove-button-style">
@@ -65,6 +65,7 @@ import { computed } from 'vue';
 import { navTo } from '@/components/utils/PageAction';
 import { navTo } from '@/components/utils/PageAction';
 import { confirm } from '@/components/dialog/CommonRoot';
 import { confirm } from '@/components/dialog/CommonRoot';
 import { useAuthStore } from '@/store/auth';
 import { useAuthStore } from '@/store/auth';
+import { useRequireLogin } from '@/common/composeabe/RequireLogin';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
 import CellGroup from '@/components/basic/CellGroup.vue';
 import CellGroup from '@/components/basic/CellGroup.vue';
 import Cell from '@/components/basic/Cell.vue';
 import Cell from '@/components/basic/Cell.vue';
@@ -88,6 +89,7 @@ const UserHead = 'https://mncdn.wenlvti.net/app_static/xiangyuan/images/user/ava
 const authStore = useAuthStore();
 const authStore = useAuthStore();
 const userInfo = computed(() => authStore.isLogged ? authStore.userInfo : null);
 const userInfo = computed(() => authStore.isLogged ? authStore.userInfo : null);
 const volunteerInfoLoader = useSimpleDataLoader(async () => await VillageApi.getVolunteerInfo(), true);
 const volunteerInfoLoader = useSimpleDataLoader(async () => await VillageApi.getVolunteerInfo(), true);
+const { requireLogin } = useRequireLogin();
 
 
 function goUserProfile() {
 function goUserProfile() {
   userInfo.value ? navTo('/pages/user/update/profile') : navTo('/pages/user/login');
   userInfo.value ? navTo('/pages/user/update/profile') : navTo('/pages/user/login');