Procházet zdrojové kódy

📦 首页精选记忆更换和对接

快乐的梦鱼 před 1 měsícem
rodič
revize
e0a5c34d27

+ 2 - 1
src/api/inhert/VillageInfoApi.ts

@@ -113,6 +113,7 @@ export class CommonInfoModel extends DataModel<CommonInfoModel> {
   villageId = 0;
   villageVolunteerId = 0;
   villageName = '';
+  villageVolunteerAvatar = '';
   villageVolunteerName = '';
   contentId = 0;
   name = '';
@@ -245,7 +246,7 @@ export class VillageInfoApi extends AppServerRequestModule<DataModel> {
     collectModuleId: number|undefined,
     subId: number|undefined,
     subKey: string|undefined,
-    villageId: number,
+    villageId: number|undefined,
     villageVolunteerId: number|undefined,
     catalogId?: number|undefined,
     page?: number,

+ 5 - 3
src/components/display/parse/ParseNodeRender.vue

@@ -2,13 +2,14 @@
   <!-- 节点渲染 -->
 
   <!-- 图片 -->
-  <image 
+  <Image
     v-if="node.tag === 'img'" 
     :id="node.attrs?.id" 
+    mode="widthFix" 
     :class="'_img ' + (node.attrs?.class || '')" 
     :style="node.attrs?.style || {}" 
-    :src="node.attrs?.src || ''" 
-    mode="widthFix" 
+    :src="node.attrs?.src as string || ''" 
+    :touchable="true"
     @click="preview(node.attrs?.src as string)"
   />
   
@@ -177,6 +178,7 @@ import { computed, inject, ref, type Ref } from 'vue';
 import ParseNodeRender from './ParseNodeRender.vue';
 import type { ParseNode } from './Parse';
 import InjectMPRender from '@/common/components/rich/InjectMPRender.vue';
+import Image from '@/components/basic/Image.vue';
 
 const props = withDefaults(defineProps<{
   node: ParseNode;

+ 1 - 0
src/pages.json

@@ -215,6 +215,7 @@
       "path": "pages/home/discover/details",
       "style": {
         "navigationBarTitleText": "发现详情页",
+        "navigationStyle": "custom",
         "enablePullDownRefresh": true
       }
     },

+ 36 - 11
src/pages/home/discover/details.vue

@@ -1,8 +1,12 @@
 <template>
   <FlexCol :padding="[0,0,50,0]">
+    <FlexCol position="absolute" :zIndex="100" :inset="{ l: 0, r: 0, t: 0 }">
+      <StatusBarSpace />
+      <NavBar :title="loader.content.value?.title || '文章详情'" leftButton="back" />
+    </FlexCol>
     <SimplePageContentLoader :loader="loader">
       <template v-if="loader.content.value">
-        <FlexCol :gap="20">
+        <FlexCol gap="games">
           <swiper 
             v-if="loader.content.value.images.length > 0"
             circular 
@@ -36,14 +40,24 @@
             width="100%"
             mode="widthFix"
           />
-          <FlexCol :padding="30" :gap="20">
-            <H3 class="size-ll color-title-text">{{ loader.content.value.title }}</H3>
-            <FlexRow :gap="20">
-              <Text v-if="loader.content.value.from" color="text.second" :size="28">来源:{{ loader.content.value.from }}</Text>
-              <Text v-if="loader.content.value.keywords" color="text.second" :size="28">{{ loader.content.value.keywords.join(' ') }}</Text>
-              <Text color="text.second" :size="28">{{ DataDateUtils.formatDate(loader.content.value.publishAt, 'YYYY-MM-dd') }}</Text>
-            </FlexRow>
-          </FlexCol>
+          <FlexRow justify="space-between" padding="padding.md" >
+            <FlexCol gap="gap.md">
+              <H3 class="size-ll color-title-text">{{ loader.content.value.title }}</H3>
+              <FlexRow gap="gap.md">
+                <Text v-if="loader.content.value.keywords" color="text.second" :size="28">{{ loader.content.value.keywords.join(' ') }}</Text>
+                <Text color="text.second" :size="28">{{ DataDateUtils.formatDate(loader.content.value.publishAt, 'YYYY-MM-dd') }}</Text>
+              </FlexRow>
+            </FlexCol>
+            <Touchable align="center" gap="gap.md" @click="handleGoUserDetails">
+              <Avatar
+                :src="loader.content.value.villageVolunteerAvatar"
+                width="50"
+                height="50"
+                radius="radius.md"
+              />
+              <Text class="size-ll color-title-text">{{ loader.content.value.villageVolunteerName }}</Text>
+            </Touchable>
+          </FlexRow>
           <FlexCol :padding="[0,30,30,30]">
             <ImageBlock3
               :src="loader.content.value.image"
@@ -52,6 +66,7 @@
               radius="radius.md"
               :title="loader.content.value.villageName"
               :desc="`${loader.content.value.villageProvince}${loader.content.value.villageCity}`"
+              @click="handleGoVillageDetails(loader.content.value.villageId)"
             />
           </FlexCol>
           <FlexCol :padding="30">
@@ -88,7 +103,7 @@ import { computed } from "vue";
 import { useSimpleDataLoader } from "@/components/composeabe/loader/SimpleDataLoader";
 import { useSwiperImagePreview } from "@/common/composeabe/SwiperImagePreview";
 import { useLoadQuerys } from "@/components/composeabe/LoadQuerys";
-import { navTo } from "@/components/utils/PageAction";
+import { backAndCallOnPageBack, navTo } from "@/components/utils/PageAction";
 import { onShareTimeline, onShareAppMessage } from "@dcloudio/uni-app";
 import { DataDateUtils } from "@imengyu/js-request-transform";
 import SimplePageContentLoader from "@/components/loader/SimplePageContentLoader.vue";
@@ -98,12 +113,15 @@ import AppCofig from "@/common/config/AppCofig";
 import VillageInfoApi from "@/api/inhert/VillageInfoApi";
 import FlexRow from "@/components/layout/FlexRow.vue";
 import FlexCol from "@/components/layout/FlexCol.vue";
-import Icon from "@/components/basic/Icon.vue";
 import Image from "@/components/basic/Image.vue";
 import Text from "@/components/basic/Text.vue";
 import H5 from "@/components/typography/H5.vue";
 import H3 from "@/components/typography/H3.vue";
 import ImageBlock3 from "@/components/display/block/ImageBlock3.vue";
+import Avatar from "@/components/display/Avatar.vue";
+import Touchable from "@/components/feedback/Touchable.vue";
+import StatusBarSpace from "@/components/layout/space/StatusBarSpace.vue";
+import NavBar from "@/components/nav/NavBar.vue";
 
 const { onPreviewImage } = useSwiperImagePreview(() => loader.content.value?.images || []);
 const emptyContent = computed(() => (loader.content.value?.content || '').trim() === '');
@@ -133,6 +151,13 @@ function goDetails(id: number) {
   });
 }
 
+function handleGoUserDetails(id: number) {
+  navTo('/pages/home/village/volunteer/detail', { id: loader.content.value?.villageVolunteerId });
+}
+function handleGoVillageDetails(id: number) {
+  backAndCallOnPageBack('goVillage', { id });
+}
+
 function getPageShareData() {
   if (!loader.content.value)
     return { title: '文章详情', imageUrl: '' }

+ 39 - 13
src/pages/home/index.vue

@@ -56,7 +56,7 @@
         :city="currentCity"
         :lonlat="currentLocation.currentLonlat.value"
         @getCurrentLonlat="currentLocation.getCurrentExactLocation"
-        @selectVillage="goDetails"
+        @selectVillage="handleGoVillageDetails"
         @regionChanged="currentRegion=$event"
       >
         <NoticeBar 
@@ -132,14 +132,14 @@
       <HomeTitle title="乡村排名" showMore @moreClicked="navTo('/pages/home/village/rank/village', {
         regionId: currentRegion ?? undefined,
       })" />
-      <VillageRankList :list="villageRankListLoader.content.value ?? []" :jumpToSingle="false" @goDetails="goDetails" />
+      <VillageRankList :list="villageRankListLoader.content.value ?? []" :jumpToSingle="false" @handleGoVillageDetails="handleGoVillageDetails" />
 
       <HomeTitle title="志愿者排名" showMore :lightCount="3" @moreClicked="navTo('/pages/home/village/rank/volunteer', {
         regionId: currentRegion ?? undefined,
       })" />
       <VillageUserRankList 
         :list="villageUserRankListLoader.content.value ?? []" 
-        @goDetails="navTo('/pages/home/village/volunteer/detail', { id: $event.id })"
+        @handleGoVillageDetails="navTo('/pages/home/village/volunteer/detail', { id: $event.id })"
       />
 
       <HomeTitle title="精选记忆">
@@ -157,11 +157,28 @@
           </Touchable>
         </template>
       </HomeTitle>
+
+      <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.villageVolunteerName ?? ''"
+              :likes="0"
+              :isLike="false"
+              @click="handleGoRecommendDetails(item)"
+            />
+          </MasonryGridItem>
+        </MasonryGrid>
+      </SimplePageListLoader>
+
     </FlexCol>
-    <OfficialAccountPublishWrap
-      topic="亮乡源" 
-      @publishsuccess="onPublishSuccess"
-    />
 
     <Height :height="200" />
 
@@ -181,7 +198,7 @@
       round
       size="80vh"
     >
-      <VillageMyFollow @goDetails="goDetails" />
+      <VillageMyFollow @handleGoVillageDetails="handleGoRecommendDetails" />
     </Popup>
 
     <IntroClamTip ref="introClamTipRef" @apply="handleLightVillage" />
@@ -202,6 +219,7 @@ import { useUserTools } from '@/common/composeabe/UserTools';
 import { ArrayUtils, waitTimeOut } from '@imengyu/imengyu-utils';
 import { toast } from '@/components/utils/DialogAction';
 import { navTo } from '@/components/utils/PageAction';
+import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
 import Image from '@/components/basic/Image.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
 import FlexRow from '@/components/layout/FlexRow.vue';
@@ -221,17 +239,20 @@ import StatusBarSpace from '@/components/layout/space/StatusBarSpace.vue';
 import LightVillageApi, { VillageListItem } from '@/api/light/LightVillageApi';
 import type { CityItem } from '@/api/map/MapApi';
 import Width from '@/components/layout/space/Width.vue';
-import OfficialAccountPublishWrap from '@/common/components/OfficialAccountPublishWrap.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 IntroClamTip from './village/dialogs/IntroClamTip.vue';
 import MemoryTimeOut from '@/components/composeabe/MemoryTimeOut';
 import Touchable from '@/components/feedback/Touchable.vue';
 import Icon from '@/components/basic/Icon.vue';
 import Text from '@/components/basic/Text.vue';
-import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
 import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
+import { useSimplePageListLoader } from '@/components/composeabe/loader/SimplePageListLoader';
+import VillageInfoApi, { type CommonInfoModel } from '@/api/inhert/VillageInfoApi';
+import SimplePageListLoader from '@/components/loader/SimplePageListLoader.vue';
 
 const emit = defineEmits(['goVillage']);
-const { onPublishSuccess } = useOfficialAccount();
 const authStore = useAuthStore();
 const villageStore = useVillageStore();
 const themeContext = useTheme();
@@ -305,14 +326,19 @@ const activityLoader = useSimpleDataLoader(async () => {
 
   ];
 });
-
+const recommendLoader = useSimplePageListLoader(20, async (page, pageSize) => {
+  return await VillageInfoApi.getListForDiscover(page, pageSize);
+}, true);
 
 watch(currentRegion, async (newVal) => {
   await villageRankListLoader.reload();
   await villageUserRankListLoader.reload();
 });
 
-async function goDetails(item: VillageListItem) {
+function handleGoRecommendDetails(item: CommonInfoModel) {
+  navTo(`/pages/home/discover/details`, { id: item.id });
+}
+async function handleGoVillageDetails(item: VillageListItem) {
   showMyFollowPopup.value = false;
   const details = await LightVillageApi.getVillageDetails(item.id);
   villageStore.setCurrentVillage(details);

+ 6 - 3
src/pages/index.vue

@@ -80,9 +80,9 @@ const { querys } = useLoadQuerys({
   }
 });
 
-async function loadShareVillageInfo() {
+async function loadShareVillageInfo(id?: number) {
   try {
-    const res = await LightVillageApi.getVillageDetails(querys.value.villageId as number);
+    const res = await LightVillageApi.getVillageDetails(id ?? querys.value.villageId as number);
     villageStore.setCurrentVillage(res);
   } catch (error) {
     console.error(error);
@@ -139,6 +139,9 @@ defineExpose({
   onPageBack: (name: string, data: Record<string, unknown>) => {
     if (data.type === 'goVillage') {
       tabIndex.value = 1;
+      if (data.id) {
+        loadShareVillageInfo(data.id as number);
+      }
     } else if (name === 'paySuccessAndRefresh') {
       paySuccessAndRefresh();
     }
@@ -152,7 +155,7 @@ onShareTimeline(() => {
 })
 onMounted(() => {
   if (isDevEnv) {
-    tabIndex.value = 1;
+    //tabIndex.value = 1;
   }
 })
 </script>