Browse Source

fix:首页样式优化--时间选择器bug修复

jiayubo 4 days ago
parent
commit
0d58d0b5d1

+ 164 - 138
components/Services/services.vue

@@ -1,28 +1,33 @@
 <template>
   <view>
-
-    <!-- <view class="home-swiper">
-      <view v-if="ValueZoneSwiper.length > 0">
-        <up-swiper :list="ValueZoneSwiper" :indicator="false" indicatorMode="line" circular></up-swiper>
-      </view>
-    </view> -->
     <up-waterfall>
       <template #left>
         <view class="demo-warter" v-for="(item, index) in props.leftList" :key="index" @click="goToDetail(item)">
-          <up-lazy-load threshold="50" border-radius="10" :image="item.volunteerPicture" :index="index"
-            mode="aspectFill"></up-lazy-load>
-          <view class="demo-title">
-            {{ item.businessTierName }}
-          </view>
-          <view class="demo-skillDescribe">
-            {{ item.skillDescribe }}
-          </view>
-          <view class="demo-PriceDome">
-            <view class="demo-price">
-              <image :src="item.volunteerPicture" class="name-image"></image>
-              {{ item.name }}
+          <view v-if="item.type == 'slideshow'" class="home-swiper">
+            <view v-if="ValueZoneSwiper.length > 0">
+              <up-swiper :list="ValueZoneSwiper" :indicator="false" class="Up-swiper"></up-swiper>
             </view>
           </view>
+
+          <template v-else>
+            <up-lazy-load threshold="50" border-radius="10" :image="item.volunteerPicture" :index="index"
+              mode="aspectFill"></up-lazy-load>
+            <view class="demo-title-container">
+              <view class="demo-title">
+                {{ item.businessTierName }}
+              </view>
+            </view>
+
+            <view class="demo-skillDescribe">
+              {{ item.skillDescribe }}
+            </view>
+            <!-- <view class="demo-PriceDome">
+              <view class="demo-price">
+                <image :src="item.volunteerPicture" class="name-image"></image>
+                {{ item.name }}
+              </view>
+            </view> -->
+          </template>
         </view>
       </template>
 
@@ -30,18 +35,20 @@
         <view class="demo-warter" v-for="(item, index) in props.rightList" :key="index" @click="goToDetail(item)">
           <up-lazy-load threshold="50" border-radius="10" :image="item.volunteerPicture" :index="index"
             mode="aspectFill"></up-lazy-load>
-          <view class="demo-title">
-            {{ item.businessTierName }}
+          <view class="demo-title-container">
+            <view class="demo-title">
+              {{ item.businessTierName }}
+            </view>
           </view>
           <view class="demo-skillDescribe">
             {{ item.skillDescribe }}
           </view>
-          <view class="demo-PriceDome">
+          <!-- <view class="demo-PriceDome">
             <view class="demo-price">
               <image :src="item.volunteerPicture" class="name-image"></image>
               {{ item.name }}
             </view>
-          </view>
+          </view> -->
         </view>
       </template>
     </up-waterfall>
@@ -49,127 +56,146 @@
 </template>
 
 <script setup>
-	const props = defineProps({
-		leftList: {
-			type: Array,
-			default: () => []
-		},
-		rightList: {
-			type: Array,
-			default: () => []
-    },
-    ValueZoneSwiper: {
-      type: Array,
-      default: () => []
-    }
-	});
-
-	const goToDetail = async (item) => {
-		const params = {
-			volunteerId: item.volunteerId, // 获取 volunteerId
-			serviceCategory: item.serviceCategory, // 获取 serviceCategory
-			businessManagementId: item.businessManagementId, //获取 businessManagementId
-		};
-		const data = encodeURIComponent(JSON.stringify(params))
-		console.log(data, '>>>>>data');
-		uni.navigateTo({
-			url: `/pages_home/pages/Volunteerside/goodsDetails?params=${data}`
-		});
-	}
+const props = defineProps({
+  leftList: {
+    type: Array,
+    default: () => []
+  },
+  rightList: {
+    type: Array,
+    default: () => []
+  },
+  ValueZoneSwiper: {
+    type: Array,
+    default: () => []
+  }
+});
+
+const goToDetail = async (item) => {
+  const params = {
+    volunteerId: item.volunteerId, // 获取 volunteerId
+    serviceCategory: item.serviceCategory, // 获取 serviceCategory
+    businessManagementId: item.businessManagementId, //获取 businessManagementId
+  };
+  const data = encodeURIComponent(JSON.stringify(params))
+  console.log(data, '>>>>>data');
+  uni.navigateTo({
+    url: `/pages_home/pages/Volunteerside/goodsDetails?params=${data}`
+  });
+}
 </script>
 
-<style scoped>
-
+<style scoped lang="scss">
 /* 轮播图片 */
-.home-swiper{
+.home-swiper {
   width: 340rpx;
+  height: 516rpx;
+  .Up-swiper {
+    width: 340rpx;
     height: 516rpx;
-  margin-top: 25rpx;
-  /* margin-left: 10rpx; */
-  margin-right: 25rpx;
+  }
 }
 
-	.demo-warter {
-		border-radius: 8px;
-		margin: 5px;
-		background-color: #ffffff;
-		/* padding: 5px; */
-	}
-
-	.u-close {
-		position: absolute;
-		top: 32rpx;
-		right: 32rpx;
-	}
-
-	.demo-image {
-		width: 100%;
-		border-radius: 4px;
-	}
-
-	.demo-title {
-		font-size: 25rpx;
-		margin-top: 5px;
-		color: #ccc;
-		/* margin-left: 15rpx; */
-		display: -webkit-box;
-		-webkit-box-orient: vertical;
-		-webkit-line-clamp: 3;
-		overflow: hidden;
-		text-overflow: ellipsis;
-		word-break: break-all;
-	}
-
-	.demo-skillDescribe {
-		font-size: 30rpx;
-		margin-top: 5px;
-		color: black;
-		display: -webkit-box;
-		-webkit-box-orient: vertical;
-		-webkit-line-clamp: 2;
-		overflow: hidden;
-		text-overflow: ellipsis;
-		word-break: break-all;
-	}
-
-	.demo-img {
-		width: 40rpx;
-		height: 40rpx;
-		border-radius: 50%;
-
-	}
-
-	.demo-PriceDome {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		width: 100%;
-		margin-top: 15rpx;
-	}
-
-	.demo-price {
-		display: flex;
-		align-items: center;
-		flex: 1;
-		overflow: hidden;
-		/* 防止内容溢出 */
-	}
-
-	.name-image {
-		width: 40rpx;
-		height: 40rpx;
-		margin-right: 10rpx;
-		border-radius: 50%;
-	}
-
-	.name-text {
-		white-space: nowrap;
-		/* 禁止换行 */
-		overflow: hidden;
-		/* 超出部分隐藏 */
-		text-overflow: ellipsis;
-		/* 显示省略号 */
-		max-width: 120rpx;
-		/* 6个中文字符大约占120rpx */
-	}
+.demo-warter {
+  border-radius: 8px;
+  margin: 5px;
+  background-color: #ffffff;
+}
+
+.u-close {
+  position: absolute;
+  top: 32rpx;
+  right: 32rpx;
+}
+
+.demo-image {
+  width: 100%;
+  border-radius: 4px;
+}
+
+.demo-title-container {
+ 
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  padding: 4rpx 12rpx;
+  // z-index: 0;
+  margin-top: 10rpx;
+  border-radius: 10rpx;
+  box-sizing: border-box;
+  border: 1rpx solid rgba(237, 93, 49, 0.8);
+}
+
+.demo-title {
+
+  font-size: 22rpx;
+  color: #ED5D31;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 3;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  word-break: break-all;
+}
+
+.demo-skillDescribe {
+  width: 298rpx;
+  height: 73rpx;
+
+  font-family: PingFang SC;
+  font-size: 26rpx;
+  font-weight: 500;
+  line-height: 36rpx;
+  letter-spacing: normal;
+  color: #141414;
+  margin-top: 5px;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  word-break: break-all;
+}
+
+.demo-img {
+  width: 40rpx;
+  height: 40rpx;
+  border-radius: 50%;
+
+}
+
+.demo-PriceDome {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+  margin-top: 15rpx;
+}
+
+.demo-price {
+  display: flex;
+  align-items: center;
+  flex: 1;
+  overflow: hidden;
+  /* 防止内容溢出 */
+}
+
+.name-image {
+  width: 40rpx;
+  height: 40rpx;
+  margin-right: 10rpx;
+  border-radius: 50%;
+}
+
+.name-text {
+  white-space: nowrap;
+  /* 禁止换行 */
+  overflow: hidden;
+  /* 超出部分隐藏 */
+  text-overflow: ellipsis;
+  /* 显示省略号 */
+  max-width: 120rpx;
+  /* 6个中文字符大约占120rpx */
+}
 </style>

+ 42 - 36
components/its-calendar/its-calendar.vue

@@ -72,7 +72,7 @@ export default {
     businessTierName: {
       type: String,
       default: '',
-    },
+    }
   },
   data() {
     return {
@@ -206,6 +206,8 @@ export default {
     },
 
     handleTimeClick(item) {
+      this.$emit('changeMinQuantityMax', 99999)
+      
       this.upItem = item
 
       const durationMs = this.businessDuration * this.minQuantity * 60 * 1000
@@ -215,23 +217,27 @@ export default {
       const currentDate = this.timeArr[this.day_index]
 
       // 1. 判断当前时间是否在任何已预约时间段的服务时长范围内
-      let inReservedRange = false
-      for (let slot of slots) {
-        if (slot.hasReservation === 1) {
-          const reservedTime =
-            slot.timeStamp > 9999999999 ? slot.timeStamp : slot.timeStamp * 1000
-          const start = reservedTime - durationMs
-          const end = reservedTime + durationMs
-          if (itemTime >= start && itemTime < end) {
-            inReservedRange = true
-            break
-          }
-        }
-      }
-      if (inReservedRange) {
-        uni.showToast({ title: '服务时长不足,请选择其他时间段', icon: 'none' })
-        return false
-      }
+      // let inReservedRange = false
+
+      // console.log(slots, '>>>>>>slots');
+      // for (let slot of slots) {
+      //   if (slot.hasReservation === 1) {
+      //     const reservedTime =
+      //       slot.timeStamp > 9999999999 ? slot.timeStamp : slot.timeStamp * 1000
+      //     const start = reservedTime - durationMs
+      //     const end = reservedTime + durationMs
+      //     if (itemTime >= start && itemTime < end) {
+      //       inReservedRange = true
+      //       break
+      //     }
+      //   }
+      // }
+      // if (inReservedRange) {
+      //   console.log('走到了这里');
+        
+      //   uni.showToast({ title: '服务时长不足,请选择其他时间段', icon: 'none' })
+      //   return false
+      // }
 
       // 2. 判断当前点击时间与所有已选时间段的服务时长有无重叠(多选判断)
       const selectedArr = this.selectedTimeSlots[currentDate] || []
@@ -330,23 +336,23 @@ export default {
       })
 
       // 1. 检查是否与已预约时间冲突
-      let inReservedRange = false
-      for (let slot of slots) {
-        if (slot.hasReservation === 1) {
-          const reservedTime =
-            slot.timeStamp > 9999999999 ? slot.timeStamp : slot.timeStamp * 1000
-          const start = reservedTime - durationMs
-          const end = reservedTime + durationMs
-          if (itemTime >= start && itemTime < end) {
-            inReservedRange = true
-            break
-          }
-        }
-      }
-      if (inReservedRange) {
-        uni.showToast({ title: '服务时长不足,请选择其他时间段', icon: 'none' })
-        return false
-      }
+      // let inReservedRange = false
+      // for (let slot of slots) {
+      //   if (slot.hasReservation === 1) {
+      //     const reservedTime =
+      //       slot.timeStamp > 9999999999 ? slot.timeStamp : slot.timeStamp * 1000
+      //     const start = reservedTime - durationMs
+      //     const end = reservedTime + durationMs
+      //     if (itemTime >= start && itemTime < end) {
+      //       inReservedRange = true
+      //       break
+      //     }
+      //   }
+      // }
+      // if (inReservedRange) {
+      //   uni.showToast({ title: '服务时长不足,请选择其他时间段', icon: 'none' })
+      //   return false
+      // }
 
       // 2. 检查是否有足够的后续时间段
       const seconds = this.businessDuration * this.minQuantity * 60
@@ -387,7 +393,7 @@ export default {
       // 	}
       // });
 
-      this.hosts(item)
+      // this.hosts(item)
     },
 
     // 点击日期

+ 45 - 7
pages/index.vue

@@ -1,7 +1,7 @@
 <template>
   <view>
     <!-- 首页顶部定位区域 -->
-    <view class="home-banner">
+    <view class="home-banner" :class="{ 'home-banner-with-bg': showAddressBg }">
       <view class="home-banner-left" @click="cityClick">
         <img src="@/static/uview/common/map-pin-fill@1x.png" alt="" class="map-pin-fill">
         <text class="address-text">{{ data.address.name }}</text>
@@ -69,13 +69,16 @@
         <RankingList v-if="userType === 2" />
       </view> -->
     <custom-tab-bar page="home" class="customTabBar" />
+
+    <!-- 底部安全区域,防止内容被TabBar遮挡 -->
+    <view class="safe-area-bottom"></view>
   </view>
 </template>
 
 <script setup>
 import { ref, reactive, onMounted } from 'vue'
 import { provide } from 'vue'
-import { onLoad, onShow, onReachBottom, onUnload } from '@dcloudio/uni-app'
+import { onLoad, onShow, onReachBottom, onUnload, onPageScroll } from '@dcloudio/uni-app'
 import RankingList from '@/pages/common/rankingList/index.vue'
 import ServIces from '@/components/Services/services.vue'
 import { Client } from '@/components/Client/new_file.vue'
@@ -177,13 +180,13 @@ const getList = async () => {
 
     // 如果是第一页,先清空
     if (pages.value.current === 1) {
-      leftList.value = []
+      leftList.value = [{ type: 'slideshow'}]
       rightList.value = []
     }
 
     // 每次都追加新数据
     res.rows.forEach((item, index) => {
-      index % 2 !== 0 ? leftList.value.push(item) : rightList.value.push(item)
+      index % 2 !== 0 ? rightList.value.push(item) : leftList.value.push(item)
     })
     console.log('home', leftList.value, rightList.value);
 
@@ -282,6 +285,14 @@ onShow(() => {
 
 const addresstree = ref([])
 
+const showAddressBg = ref(false)
+
+// Handle page scroll event
+onPageScroll(e => {
+  // Show background when scrolled past threshold (middle of carousel, around 200px)
+  showAddressBg.value = e.scrollTop > 180
+})
+
 onMounted(async () => {
 
   const token = getToken();
@@ -312,14 +323,34 @@ onUnload(() => { })
 <style scoped lang="scss">
 // 首页顶部区域-轮播图
 .home-banner {
-  position: absolute;
+  position: fixed;
   z-index: 130;
+  // top: v-bind('globalData.statusBarHeight + 10 + "px"');
+  left: 0;
+  height: 90px;
+  width: 100%;
+  padding: 10rpx 0;
+  transition: background-color 0.3s ease;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+
+  &.home-banner-with-bg {
+    // background-color: rgba(255, 255, 255, 0.9);
+    // box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
+    background: #FAFBF0;
+    height: 90px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+  }
 
-  // top: 110rpx;
   .home-banner-left {
     display: flex;
     align-items: center;
-    justify-content: center;
+    padding-left: 10rpx;
+    box-sizing: border-box;
+    margin-top:80rpx;
 
     .map-pin-fill {
       width: 34rpx;
@@ -359,5 +390,12 @@ onUnload(() => { })
   margin-top: 80rpx;
   margin-left: 25rpx;
   margin-right: 25rpx;
+  margin-bottom: 120rpx;
+}
+
+/* 底部安全区域 */
+.safe-area-bottom {
+  height: 150rpx;
+  width: 100%;
 }
 </style>

+ 13 - 0
pages_home/pages/Volunteerside/goodsDetails.vue

@@ -162,6 +162,7 @@
                 class="calendar-component"
                 @getByDate="getByDate"
                 @getByTime="getByTime"
+                @changeMinQuantityMax="changeMinQuantityMax"
               ></its-calendar>
             </view>
           </view>
@@ -680,6 +681,12 @@ const getByTime = (timeObj) => {
     selectedTimes.value.splice(index, 1)
   }
 
+  console.log(selectedTimes, '.>>>selectedTimes');
+  
+
+  console.log(selectedTimes.value.length, '>>>>>>selectedTimes.value.length');
+  
+
   totalTimes.value = selectedTimes.value.length // 更新点击次数
 }
 
@@ -701,6 +708,8 @@ const computeMoney = computed(() => {
   //   singleQuantity.value,
   //   '>>>>>>	console.log(totalTimes.value * businessPrice.value * minQuantity.value);'
   // )
+  console.log(totalTimes.value, businessPrice.value, singleQuantity.value, '>>>>>>>>7777777');
+  
   return totalTimes.value * businessPrice.value * singleQuantity.value
 })
 
@@ -863,6 +872,10 @@ const handlePaymentMethodChange = (value) => {
   }
 }
 
+const changeMinQuantityMax = (val = 99999) => {
+  minQuantityMax.value = val
+}
+
 onMounted(async () => {
   await getListTime()
 })