Procházet zdrojové kódy

💊 修复优化点亮逻辑问题

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

+ 11 - 0
CLAUDE.md

@@ -118,6 +118,17 @@ isFeaturedVillage = 0;
 
 - 使用 `<script setup lang="ts">` 组合式 API
 - 样式使用 `<style lang="scss" scoped>`
+## Path Aliases
+
+- `@/` → `src/`
+
+## Coding Style
+
+- 函数名使用小驼峰 (`camelCase`),组件名使用大驼峰 (`PascalCase`),组件属性名优先小驼峰
+- 优先将大功能组件拆分为小组件 + composable 组合式函数
+- 子组件/composable 的放置规则:
+  - 仅当前模块使用 → 放在同级 `components/` 或 `composables/` 目录下
+  - 项目通用 → 放在 `src/common/components/` 或 `src/common/composables/` 下
 
 ## API 文档
 

+ 8 - 3
src/common/components/FrameButton.vue

@@ -12,7 +12,7 @@
   >
     <ActivityIndicator v-if="loading" :size="iconSize" :color="primary ? 'white' : 'text.content'" />
     <Icon v-if="icon" :icon="icon" :size="iconSize" :color="primary ? 'white' : 'text.content'" />
-    <Text :text="text" :wrap="false" fontConfig="lightTitle" :fontSize="fontSize" :color="primary ? 'white' : 'text.content'" />
+    <Text v-if="text" v-bind="textProps" :text="text" :wrap="false" fontConfig="lightTitle" :fontSize="fontSize" :color="primary ? 'white' : 'text.content'" />
   </BackgroundImageButton>
 </template>
 
@@ -21,25 +21,30 @@ import ActivityIndicator from '@/components/basic/ActivityIndicator.vue';
 import BackgroundImageButton from '@/components/basic/BackgroundImageButton.vue';
 import Icon from '@/components/basic/Icon.vue';
 import Text from '@/components/basic/Text.vue';
+import type { ThemePaddingOrMarginType } from '@/components/theme/ThemeDefine';
 import { computed } from 'vue';
 
 const props = withDefaults(defineProps<{
-  text: string;
+  text?: string;
+  textProps?: object;
   primary?: boolean;
   size?: 'large' | 'midium' | 'small';
   width?: string|number;
+  padding?: ThemePaddingOrMarginType,
   innerStyle?: object;
   loading?: boolean;
   touchable?: boolean;
   icon?: string;
 }>(), {
-  text: '去发布',
+  text: '',
   primary: false,
   touchable: true,
   size: 'large',
 }); 
 
 const padding = computed(() => {
+  if (typeof props.padding !== 'undefined') 
+    return props.padding;
   switch (props.size) {
     case 'large': return [20, 36];
     case 'midium': return [18, 20];

+ 5 - 0
src/common/components/SimpleDropDownPicker.vue

@@ -1,6 +1,7 @@
 <template>
   <view 
     class="simple-dropdown-box" 
+    :style="{ backgroundColor }"
     @click="show=true"
   >
     <picker @change="bindPickerChange" :value="selectedIndex" :range="columns" range-key="name">
@@ -18,6 +19,10 @@ export interface SimpleDropDownPickerItem {
 }
 
 const props = defineProps({	
+  backgroundColor: {
+    type: String,
+    default: '#FFFFFF',
+  },
   columns: {
     type: Object as PropType<SimpleDropDownPickerItem[]|null>,
     default: null,

+ 4 - 3
src/common/components/box/BoxMid.vue

@@ -2,7 +2,9 @@
 import BackgroundBox from '@/components/display/block/BackgroundBox.vue';
 import type { FlexProps } from '@/components/layout/FlexView.vue';
 
-const props = defineProps<FlexProps>();
+const props = withDefaults(defineProps<FlexProps>(), {
+  padding: 32,
+});
 
 defineOptions({
   options: {
@@ -13,11 +15,10 @@ defineOptions({
 
 <template>
   <BackgroundBox
-    v-bind="props"
     backgroundImage="https://xy.wenlvti.net/app_static/images/village/BoxMid.png"
     :backgroundCutBorder="32"
     :backgroundCutBorderSize="36"
-    :padding="32"
+    v-bind="props"
   >
     <slot />
   </BackgroundBox>

+ 11 - 8
src/pages/home/components/LightMap.vue

@@ -52,18 +52,18 @@
       <FlexRow align="center" justify="space-between">
         <view v-if="small"></view>
         <template v-else>
-          <NButton
+          <FrameButton
             :icon="searchKeyword ? 'close' : 'search'" 
-            iconMargin="0"
+            :padding="30"
             @click="showSearch" 
           />
-          <FlexRow gap="gap.md" align="center">
+          <BoxMid direction="row" gap="gap.md" align="center" :padding="15">
             <NButton
               :text="city + ' ▼'"
-              color="white"
+              color="transparent"
               type="custom"
               :radius="30"
-              :padding="[30,10]"
+              :padding="30"
               :textProps="{
                 maxWidth: 150,
                 lines: 1
@@ -72,15 +72,16 @@
             />
             <SimpleDropDownPicker
               class="light-map-region-picker" 
+              backgroundColor="transparent"
               :modelValue="selectedRegion" 
               @update:modelValue="onSelectedRegion"
               :columns="regionLoader.content.value" 
             />
-          </FlexRow>
+          </BoxMid>
         </template>
-        <NButton
+        <FrameButton
           icon="navigation" 
-          iconMargin="0"
+          :padding="30"
           @click="emit('getCurrentLonlat')" 
         />
       </FlexRow>
@@ -121,6 +122,8 @@ import RegionApi from '@/api/map/RegionApi';
 import type { MapMarker } from '@/types/Map';
 import { hideLoading, loading } from '@/components/utils/DialogAction';
 import { showError } from '@/common/composeabe/ErrorDisplay';
+import FrameButton from '@/common/components/FrameButton.vue';
+import BoxMid from '@/common/components/box/BoxMid.vue';
 
 const instance = getCurrentInstance();
 const mapCtx = uni.createMapContext('prevMap', instance);

+ 38 - 19
src/pages/home/light/create-village.vue

@@ -1,5 +1,5 @@
 <template>
-  <CommonTopBanner title="点亮村社">
+  <CommonTopBanner title="点亮村社" customBack @backPressed="handleBack">
     <FlexCol padding="padding.md" gap="gap.md">
       <template v-if="step === 'selectArea'">
         <FlexRow center>
@@ -16,26 +16,29 @@
         />
       </template>
       <template v-else-if="step === 'selectVillage'">
-        <FlexCol gap="gap.md" padding="padding.md" width="600rpx">
-          <BoxMid>
-            <Touchable direction="row" gap="gap.md"center @click="handleSkipSearch()">
-              <Image src="https://xy.wenlvti.net/app_static/images/home/volunteer/IconFollows.png" :radius="20" width="70" height="70" mode="aspectFill" />
-              <Text text="以下没有我的家乡" fontConfig="lightGoldTitle" />
-            </Touchable>
-          </BoxMid>
+        <FlexCol gap="gap.md" padding="padding.md">
+          <FlexRow center>
+            <Text fontConfig="lightGoldTitle">您的家乡已经创建,是否去加入村落?</Text>
+          </FlexRow>
+          <Height :height="10" />
           <BoxMid
             v-for="(item, k) in searchedList"
             :key="k"
             justify="flex-start"
           >
-            <Touchable direction="row" gap="gap.md"center @click="handleChooseSearchedVillage(item as VillageListItem)">
-              <Image :src="item.image" :radius="20" width="70" height="70" mode="aspectFill" />
+            <Touchable direction="row" gap="gap.lg" @click="handleChooseSearchedVillage(item as VillageListItem)">
+              <Image :src="item.image" :radius="20" :width="170" :height="100" mode="aspectFill" />
               <FlexCol gap="gap.md">
                 <Text :text="item.name" fontConfig="lightGoldTitle" />
                 <Text :text="item.address" fontConfig="secondText" />
               </FlexCol>
             </Touchable>
           </BoxMid>
+          <Height :height="20" />
+          <Touchable direction="row" gap="gap.md" center @click="handleSkipSearch()">
+            <Image src="https://xy.wenlvti.net/app_static/images/home/volunteer/IconFollows.png" :radius="20" :width="40" :height="40" mode="aspectFill" />
+            <Text text="以上没有我的家乡,我要建村" fontConfig="secondText" />
+          </Touchable>
         </FlexCol>
       </template>
       <template v-else-if="step === 'inputInfo'">
@@ -123,6 +126,7 @@ import BoxMid from '@/common/components/box/BoxMid.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
 import Image from '@/components/basic/Image.vue';
 import AppCofig from '@/common/config/AppCofig';
+import Height from '@/components/layout/space/Height.vue';
 
 const { querys } = useLoadQuerys({
   villageName: '',
@@ -189,7 +193,17 @@ function handleBack() {
   if (currentFromPreData.value) {
     back();
   } else {
-    step.value = 'selectArea';
+    switch (step.value) {
+      case 'selectArea': back(); break;
+      case 'selectVillage': step.value = 'selectArea'; break;
+      case 'inputInfo': {
+        if (searchedList.value.length > 0) 
+          step.value = 'selectVillage';
+        else  
+          step.value = 'selectArea';
+        break;
+      }
+    }
   }
 }
 async function asyncLoadData(item: CascaderItem) {
@@ -227,15 +241,20 @@ async function handlePickEnd(values: CascaderItem[]) {
       latitude: Number(currentLonLat.value.latitude),
     });
     uni.showLoading();
-    step.value = 'selectVillage';
-    const searchRes = (await LightVillageApi.getVillageList({
-      areaCode: currentAreaCode.value,
-      page: 1,
-      pageSize: 10
-    })).list;
-    if (searchRes.length > 0) {
+    try {
+      step.value = 'selectVillage';
+      const searchRes = (await LightVillageApi.getVillageList({
+        areaCode: currentAreaCode.value,
+        page: 1,
+        pageSize: 10
+      })).list;
+      if (searchRes.length > 0) {
+        searchedList.value = searchRes;
+      } else {
+        step.value = 'inputInfo';
+      }
+    } finally {
       uni.hideLoading();
-      searchedList.value = searchRes;
     }
   }
 }