Bladeren bron

📦 村落相册优化

快乐的梦鱼 3 weken geleden
bovenliggende
commit
017ddee356

+ 1 - 1
src/components/basic/IconButton.vue

@@ -9,7 +9,7 @@
   >
     <Icon v-if="icon" v-bind="props" />
     <slot>
-      <Text :text="text" />
+      <Text v-if="text" :text="text" />
     </slot>
   </Touchable>
 </template>

+ 2 - 6
src/pages/home/components/LightMap.vue

@@ -163,7 +163,7 @@ const mapLoader = useSimpleDataLoader<MapMarker[]>(async () => {
   villageData.clear();
   if (!selectedRegion.value)
     return [];
-  await waitTimeOut(200);
+  await waitTimeOut(100);
   const res = (await LightVillageApi.getVillageList({
     region: selectedRegion.value,
     keyword: searchKeyword.value.trim() || undefined,
@@ -223,7 +223,6 @@ const mapLoader = useSimpleDataLoader<MapMarker[]>(async () => {
   asyncAddMarkers(list);
 
   if (nextNeedAutoFocus.value) {
-    
     if (res.length == 1) {
       mapCtx.moveToLocation({
         latitude: Number(list[0].latitude),
@@ -260,9 +259,6 @@ const mapLoader = useSimpleDataLoader<MapMarker[]>(async () => {
       }
     }
   }
-
-
-
   ready.value = true;
   return list;
 }, false, false);
@@ -284,7 +280,7 @@ async function asyncAddMarkers(list: MapMarker[]) {
       markers: batch,
     });
     if (i + BATCH_SIZE < list.length) {
-      await waitTimeOut(50);
+      await waitTimeOut(500);
     }
   }
 }

+ 12 - 17
src/pages/home/village/components/VillageGallery.vue

@@ -20,30 +20,24 @@
             touchable
             @click="goGallery"
           />
-          <FlexCol
+          <VillageGalleryUpload
             v-for="n in (3 - group.length)"
             :key="'placeholder-' + n"
             :width="200"
             :height="140"
+            @click="goGallery"
           />
         </FlexRow>
       </swiper-item>
       <swiper-item v-if="pagedImages.length === 0" >
         <FlexRow justify="space-between" gap="gap.sm">
-          <Touchable
+          <VillageGalleryUpload
             v-for="n in 3"
             :key="'placeholder-' + n"
-            direction="column"
-            radius="radius.md"
             :width="200"
             :height="140"
-            center
-            backgroundColor="background.primary"
-            @click="goGallery"
-          >
-            <Icon name="add" size="fontSize.md" />
-            <Text text="上传图片" fontConfig="secondText" />
-          </Touchable>
+            @click="goGallery" 
+          />
         </FlexRow>
       </swiper-item>
     </swiper>
@@ -51,16 +45,14 @@
 </template>
 
 <script setup lang="ts">
+import { computed } from 'vue';
+import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
+import { useAuthStore } from '@/store/auth';
 import FlexRow from '@/components/layout/FlexRow.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
 import Image from '@/components/basic/Image.vue';
-import { computed } from 'vue';
 import GalleryApi, { type GalleryItem } from '@/api/light/GalleryApi';
-import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
-import { navTo } from '@/components/utils/PageAction';
-import Touchable from '@/components/feedback/Touchable.vue';
-import Icon from '@/components/basic/Icon.vue';
-import Text from '@/components/basic/Text.vue';
+import VillageGalleryUpload from './VillageGalleryUpload.vue';
 
 const props = withDefaults(defineProps<{
   villageId: number;
@@ -69,9 +61,12 @@ const props = withDefaults(defineProps<{
 
 const emit = defineEmits(['goGallery']);
 
+const authStore = useAuthStore();
+
 const imageLoader = useSimpleDataLoader(async () => {
   return await GalleryApi.getAlbumList({
     villageId: props.villageId,
+    userId: authStore.userId,
     page: 1,
     pageSize: 18,
   });

+ 30 - 0
src/pages/home/village/components/VillageGalleryUpload.vue

@@ -0,0 +1,30 @@
+<template>
+  <Touchable
+    direction="column"
+    radius="radius.md"
+    :width="width"
+    :height="height"
+    center
+    backgroundColor="background.tertiary"
+    @click="emit('click')"
+  >
+    <Icon name="add" size="fontSize.md" />
+    <Text text="上传照片" fontConfig="secondText" />
+  </Touchable>
+</template>
+
+<script setup lang="ts">
+import Touchable from '@/components/feedback/Touchable.vue';
+import Icon from '@/components/basic/Icon.vue';
+import Text from '@/components/basic/Text.vue';
+
+const props = withDefaults(defineProps<{
+  width?: number;
+  height?: number;
+}>(), {
+  width: 200,
+  height: 140,
+});
+
+const emit = defineEmits(['click']);
+</script>

+ 77 - 32
src/pages/home/village/gallery/index.vue

@@ -2,30 +2,64 @@
   <CommonTopBanner title="村社相册">
     <FlexCol gap="gap.md" padding="padding.md">
       <SimplePageListLoader :loader="galleryLoader">
-        <FlexRow v-if="galleryLoader.list.value && galleryLoader.list.value.length > 0" wrap gap="gap.sm">
-          <Image
+        <FlexRow 
+          v-if="galleryLoader.list.value && galleryLoader.list.value.length > 0" 
+          wrap 
+          gap="gap.md"
+        >
+          <FlexCol
             v-for="item in galleryLoader.list.value"
             :key="item.id"
-            :src="item.image"
+            :width="galleryItemWidth"
+            :height="galleryItemHeight"
+            position="relative"
             radius="radius.md"
-            :width="galleryItemSize"
-            :height="galleryItemSize"
-            mode="aspectFill"
-            touchable
-            @click="previewImage(item.image)"
-          />
-          <Touchable
-            direction="column"
-            radius="radius.md"
-            :width="galleryItemSize"
-            :height="galleryItemSize"
-            center
-            backgroundColor="background.primary"
-            @click="uploadImage"
+            overflow="hidden"
           >
-            <Icon name="add" size="fontSize.md" />
-            <Text text="上传图片" fontConfig="secondText" />
-          </Touchable>
+            <Image
+              :src="item.image"
+              :width="galleryItemWidth"
+              :height="galleryItemHeight"
+              mode="aspectFill"
+              touchable
+              @click="previewImage(item.image)"
+            />
+            <IconButton 
+              v-if="item.userId === authStore.userId"
+              icon="edit-filling" 
+              shape="round" 
+              :size="30"
+              :buttonSize="50"
+              color="white"
+              backgroundColor="rgba(0,0,0,0.4)"
+              :buttonStyle="{
+                position: 'absolute',
+                right: '20rpx',
+                top: '20rpx',
+              }"
+              @click="editImage(item)" 
+            />
+            <BackgroundBox
+              position="absolute"
+              :inset="{ l: 0, r: 0, b: 0 }"
+              :padding="[20, 15]"
+              color1="transparent"
+              color2="rgba(0,0,0,0.5)"
+              direction="column"
+            >
+              <Text :text="item.desc || '相片'" color="white" fontConfig="contentText" :lines="1" />
+              <!-- <FlexRow justify="space-between" align="center">
+                <Avatar :url="item.user.avatar" :size="40" />
+                <Text :text="item.user.nickname" fontConfig="contentText" />
+              </FlexRow> -->
+            </BackgroundBox>
+          </FlexCol>
+          
+          <VillageGalleryUpload
+            :width="galleryItemWidth"
+            :height="galleryItemHeight"
+            @click="uploadImage"
+          />
         </FlexRow>
         <template #empty>
           <Empty description="还没有任何村社照片,快来上传吧">
@@ -39,43 +73,45 @@
 </template>
 
 <script setup lang="ts">
-import { useSimplePageListLoader } from '@/components/composeabe/loader/SimplePageListLoader';
 import { computed } from 'vue';
+import { useSimplePageListLoader } from '@/components/composeabe/loader/SimplePageListLoader';
+import { useAuthStore } from '@/store/auth';
 import { backAndCallOnPageBack, callPrevOnPageBack, navTo } from '@/components/utils/PageAction';
 import { useLoadQuerys } from '@/components/composeabe/LoadQuerys';
 import { confirm } from '@/components/dialog/CommonRoot';
+import Text from '@/components/basic/Text.vue';
+import BackgroundBox from '@/components/display/block/BackgroundBox.vue';
+import IconButton from '@/components/basic/IconButton.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
 import FlexRow from '@/components/layout/FlexRow.vue';
 import SimplePageListLoader from '@/components/loader/SimplePageListLoader.vue';
 import CommonTopBanner from '@/common/components/CommonTopBanner.vue';
 import Image from '@/components/basic/Image.vue';
-import Icon from '@/components/basic/Icon.vue';
 import Button from '@/components/basic/Button.vue';
-import Text from '@/components/basic/Text.vue';
-import Touchable from '@/components/feedback/Touchable.vue';
 import Empty from '@/components/feedback/Empty.vue';
 import Height from '@/components/layout/space/Height.vue';
-import GalleryApi from '@/api/light/GalleryApi';
+import GalleryApi, { type GalleryItem } from '@/api/light/GalleryApi';
+import VillageGalleryUpload from '../components/VillageGalleryUpload.vue';
+import Avatar from '@/components/display/Avatar.vue';
 
 const { querys } = useLoadQuerys({
   villageId: 0,
   maxCount: 3,
 });
 
+const authStore = useAuthStore();
+
 const galleryLoader = useSimplePageListLoader(30, async (page, pageSize) => {
   return await GalleryApi.getAlbumList({
     villageId: querys.value.villageId,
+    userId: authStore.userId,
     page,
     pageSize,
   });
 });
 
-const galleryItemSize = computed(() => {
-  const screenWidth = uni.getSystemInfoSync().windowWidth;
-  const padding = uni.upx2px(40);
-  const gap = uni.upx2px(16);
-  return Math.floor((screenWidth - padding - gap * 2) / 3);
-});
+const galleryItemWidth = 350;
+const galleryItemHeight = 230;
 
 const isOverMaxCount = computed(() => galleryLoader.total.value >= querys.value.maxCount);
 
@@ -87,10 +123,19 @@ function previewImage(url: string) {
   });
 }
 
+function editImage(item: GalleryItem) {
+  navTo(`/pages/home/village/gallery/upload`, { 
+    id: item.id,
+    villageId: querys.value.villageId,
+    desc: item.desc,
+    image: item.image,
+  });
+}
+
 function uploadImage() {
   if (isOverMaxCount.value) {
     confirm({
-      content: '您最多只能上传' + querys.value.maxCount + '张图片哦',
+      content: '您最多只能上传' + querys.value.maxCount + '张图片哦,升级村社等级可以获得更多照片上传权益',
       icon: 'prompt',
       confirmText: '去升级',
     }).then((res) => {

+ 16 - 6
src/pages/home/village/gallery/upload.vue

@@ -62,6 +62,7 @@ import Field from '@/components/form/Field.vue';
 import { backAndCallOnPageBack } from '@/components/utils/PageAction';
 import FlexRow from '@/components/layout/FlexRow.vue';
 import ProvideVar from '@/components/theme/ProvideVar.vue';
+import { useAuthStore } from '@/store/auth';
 
 const { querys } = useLoadQuerys({
   villageId: 0,
@@ -75,6 +76,7 @@ const { querys } = useLoadQuerys({
   }
 });
 
+const authStore = useAuthStore();
 const selectedImage = ref<string | null>(null);
 const desc = ref('');
 
@@ -97,12 +99,20 @@ async function submit() {
   }
   try {
     uni.showLoading({ title: '上传中...' });
-    await GalleryApi.saveVillageImageWithFile({
-      id: querys.value.id > 0 ? querys.value.id : undefined,
-      filePath: selectedImage.value,
-      villageId: querys.value.villageId,
-      desc: desc.value,
-    });
+    if (selectedImage.value.startsWith('http') && querys.value.id > 0) {
+      await GalleryApi.saveVillageImage({
+        id: querys.value.id,
+        villageId: querys.value.villageId,
+        desc: desc.value,
+      });
+    } else {
+      await GalleryApi.saveVillageImageWithFile({
+        id: querys.value.id > 0 ? querys.value.id : undefined,
+        filePath: selectedImage.value,
+        villageId: querys.value.villageId,
+        desc: desc.value,
+      });
+    }
     toast('上传成功');
     backAndCallOnPageBack('list', {
       needRefresh: true,

+ 1 - 1
src/pages/home/village/introd/tree.vue

@@ -145,6 +145,7 @@ import { useVillageStore } from '@/store/village';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
 import { useRequireLogin } from '@/common/composeabe/RequireLogin';
 import { showError } from '@/common/composeabe/ErrorDisplay';
+import { toast } from '@/components/utils/DialogAction';
 import { navTo } from '@/components/utils/PageAction';
 import { RequestApiError, SimpleTimer } from '@imengyu/imengyu-utils';
 import HomeTitle from '@/common/components/parts/HomeTitle.vue';
@@ -163,7 +164,6 @@ import TreeApi, { type BlessPackageItem, type GrowthLogFeedItem } from '@/api/li
 import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
 import BlessBuyDialog from '../dialogs/BlessBuyDialog.vue';
 import BlessSuccessDialog from '../dialogs/BlessSuccessDialog.vue';
-import { toast } from '@/components/utils/DialogAction.js';
 
 const GROWTH_FEED_COUNT = 6;
 const DEFAULT_AVATAR = 'https://xy.wenlvti.net/app_static/images/village/PlaceholderVolunteer.png';