浏览代码

Merge branch 'jyb_20250506_dev' into dev-1.2.0

jiayubo 3 月之前
父节点
当前提交
52320e0f86

+ 9 - 0
api/volunteerDetailsApi/details.js

@@ -64,6 +64,15 @@ export function volTierName(params) {
   })
 }
 
+// 模糊搜索Tabs
+export function volBusinessTypeList(params) {
+  return request({
+    url: '/core/volunteer/info/searchBusinessTypeList',
+    method: 'get',
+    params: params,
+  })
+}
+
 
 // 获取志愿者所有排班时间
 export function volunteergetTimesByDate(params) {

+ 85 - 26
components/Services/services.vue

@@ -13,15 +13,16 @@
           <template v-else>
             <up-lazy-load threshold="50" border-radius="10" :image="item.volunteerPicture" :index="index"
               mode="aspectFill"></up-lazy-load>
+            <view class="demo-skillDescribe">
+              {{ item.businessDescribe }}
+            </view>
             <view class="demo-title-container">
               <view class="demo-title">
                 {{ item.businessTierName }}
               </view>
             </view>
 
-            <view class="demo-skillDescribe">
-              {{ item.businessDescribe }}
-            </view>
+
             <view class="demo-PriceDome">
               <view class="demo-price">
                 <image :src="item.volunteerPicture" class="name-image"></image>
@@ -32,22 +33,30 @@
                 <text class="name-textNumber">1w</text>
               </view>
             </view>
+            <view class="demo-price-distance">
+              <view class="demo-price-distance-text-1">
+                <text class="demo-price-distance-text-2">¥</text>
+                <text class="demo-price-distance-text">130</text>
+              </view>
+              <button class="demo-price-distance-button" @click="goToDetail(item)">抢购</button>
+            </view>
           </template>
         </view>
       </template>
 
       <template #right>
-        <view class="demo-warter" v-for="(item, index) in props.rightList" :key="index" @click="goToDetail(item)">
+        <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-skillDescribe">
+            {{ item.businessDescribe }}
+          </view>
           <view class="demo-title-container">
             <view class="demo-title">
               {{ item.businessTierName }}
             </view>
           </view>
-          <view class="demo-skillDescribe">
-            {{ item.businessDescribe }}
-          </view>
+
           <view class="demo-PriceDome">
             <view class="demo-price">
               <image :src="item.volunteerPicture" class="name-image"></image>
@@ -58,6 +67,13 @@
               <text class="name-textNumber">1w</text>
             </view>
           </view>
+          <view class="demo-price-distance">
+            <view class="demo-price-distance-text-1">
+              <text class="demo-price-distance-text-2">¥</text>
+              <text class="demo-price-distance-text">130</text>
+            </view>
+            <button class="demo-price-distance-button" @click="goToDetail(item)">抢购</button>
+          </view>
         </view>
       </template>
     </up-waterfall>
@@ -134,17 +150,16 @@ const goToDetail = async (item) => {
 }
 
 .demo-title-container {
-
   display: flex;
   flex-direction: column;
-  justify-content: center;
-  align-items: center;
-  padding: 4rpx 12rpx;
+  // justify-content: center;
+  // align-items: center;
+  padding: 4rpx 0rpx;
   // z-index: 0;
   margin-top: 10rpx;
   border-radius: 10rpx;
   box-sizing: border-box;
-  border: 1rpx solid rgba(237, 93, 49, 0.8);
+  // border: 1rpx solid rgba(237, 93, 49, 0.8);
 }
 
 .demo-title {
@@ -160,9 +175,8 @@ const goToDetail = async (item) => {
 }
 
 .demo-skillDescribe {
-  width: 298rpx;
-  height: 73rpx;
-
+  width: 345rpx;
+  height: auto;
   font-family: PingFang SC;
   font-size: 26rpx;
   font-weight: 500;
@@ -172,7 +186,7 @@ const goToDetail = async (item) => {
   margin-top: 5px;
   display: -webkit-box;
   -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
+  -webkit-line-clamp: 1;
   overflow: hidden;
   text-overflow: ellipsis;
   word-break: break-all;
@@ -198,18 +212,63 @@ const goToDetail = async (item) => {
   overflow: hidden;
   /* 防止内容溢出 */
 }
-.image-1x{
-    width: 20rpx;
-    height: 20rpx;
-    z-index: 0;
+
+.image-1x {
+  width: 20rpx;
+  height: 20rpx;
+  z-index: 0;
+}
+
+.name-textNumber {
+  font-size: 22rpx;
+  font-weight: normal;
+  line-height: 24rpx;
+  text-align: right;
+  letter-spacing: -0.04em;
+  color: #FF6E51;
 }
-.name-textNumber{
+
+.demo-price-distance {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-top: 10rpx;
+
+  .demo-price-distance-text-1 {
+    display: flex;
+    align-items: center;
+
+    .demo-price-distance-text-2 {
+      font-family: Source Han Sans;
       font-size: 22rpx;
-      font-weight: normal;
-      line-height: 24rpx;
-      text-align: right;
-      letter-spacing: -0.04em;
-      color: #FF6E51;
+      font-weight: bold;
+      line-height: 34rpx;
+      color: #FA2922;
+    }
+  }
+
+  .demo-price-distance-text {
+    font-family: Source Han Sans;
+    font-weight: 700;
+    font-size: 40rpx;
+    font-variation-settings: "opsz" auto;
+    color: #FA2922;
+  }
+
+  .demo-price-distance-button {
+    width: 124rpx;
+    height: 51rpx;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border-radius: 36rpx;
+    background: linear-gradient(90deg, #FE534B 25%, #FD8F7C 91%);
+    box-shadow: 0rpx 1rpx 2rpx 0rpx rgba(0, 0, 0, 0.18), inset 0rpx 4rpx 10rpx 0rpx rgba(255, 221, 221, 0.3);
+    color: #FFFFFF;
+    font-size: 30rpx;
+    padding: 0;
+    margin-left: 132rpx;
+  }
 }
 
 

+ 338 - 157
pages_classify/components/Slide/index.vue

@@ -1,192 +1,373 @@
 <template>
-    <view class="slider-verify" :style="'background-color:' + sBgColor" @touchend="touchend">
-        <view class="slider-prompt" :style="success ? 'color:' + sColor : 'color:' + dColor">{{ success ? sliderText.successText : sliderText.startText }}</view>
-        <view class="slider-bg" :style="{ 'transform': 'translateX(' + oldx + 'px)', backgroundColor: dBgColor }"></view>
-        <movable-area class="slider-area" :animation="true">
-            <movable-view 
-                :style="`background-color: ${sliderText.successColor};border-color: ${success ? sBgColor : dBgColor} `"
-                :class="{ 'movable-btn': true, 'movable-success': success }" :x="x" direction="horizontal" @change="onMove"
-                :disabled="isDisable">
-                {{sliderText.btnText}}
-            </movable-view>
-        </movable-area>
+  <view class="slider-verify" :style="'background-color:' + sBgColor" @touchend="touchend">
+    <view class="slider-prompt" :style="success ? 'color:' + sColor : 'color:' + dColor">
+      <view class="arrow-group left">
+        <text class="arrow" v-for="(item, index) in leftArrows" :key="`left-${index}`" 
+              :style="{opacity: item.opacity, transform: `scale(${item.scale})`, color: arrowColor}">›</text>
+      </view>
+      {{ success ? sliderText.successText : sliderText.startText }}
+      <view class="arrow-group right">
+        <text class="arrow" v-for="(item, index) in rightArrows" :key="`right-${index}`" 
+              :style="{opacity: item.opacity, transform: `scale(${item.scale})`, color: arrowColor}">›</text>
+      </view>
     </view>
+    <view class="slider-bg" :style="{ 'transform': 'translateX(' + oldx + 'px)', backgroundColor: dBgColor }"></view>
+    <movable-area class="slider-area" :animation="true">
+      <movable-view :class="{ 'movable-btn': true, 'movable-success': success }" :style="sliderStyle" :x="x"
+        direction="horizontal" @change="onMove" :disabled="isDisable">
+        {{ sliderText.btnText }}
+      </movable-view>
+    </movable-area>
+  </view>
 </template>
 
 <script>
 export default {
-    props: {
-        //是否禁止拖动
-        disabled: {
-            type: Boolean,
-            default: false
-        },
-        //偏移量
-        offset: {
-            type: Number,
-            default: 3
-        },
-        //滑动轨道默认背景色
-        dBgColor: {
-            type: String,
-            default: '#f0f0f0'
-        },
-        //滑动轨道滑过背景色
-        sBgColor: {
-            type: String,
-            default: '#b1d7ff'
-        },
-        //默认文字颜色
-        dColor: {
-            type: String,
-            default: '#8a8a8a'
-        },
-        //成功文字颜色
-        sColor: {
-            type: String,
-            default: '#FFFFFF'
-        },
-        sliderText: {
-            type: Object,
-            default: {
-                successText:'验证通过',
-                startText:'拖动滑块验证',
-                successColor: '#72c13f',
-                btnText: 'GO'
-            }
-        },
-
+  props: {
+    //是否禁止拖动
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    //偏移量
+    offset: {
+      type: Number,
+      default: 3
+    },
+    //滑动轨道默认背景色
+    dBgColor: {
+      type: String,
+      default: '#f0f0f0'
+    },
+    //滑动轨道滑过背景色
+    sBgColor: {
+      type: String,
+      default: '#f0f0f0'
+    },
+    //默认文字颜色
+    dColor: {
+      type: String,
+      default: '#8a8a8a'
     },
-    data() {
+    //成功文字颜色
+    sColor: {
+      type: String,
+      default: '#FFFFFF'
+    },
+    // 按钮文本
+    btnType: {
+      type: String,
+      default: 'start' 
+    },
+    sliderText: {
+      type: Object,
+      default() {
         return {
-            x: 0,
-            oldx: 0,
-            success: false, //是否验证成功
-            verification: 0, //验证次数
-            isDisable: this.disabled,
-            screenWidth: 0
-        };
+          successText: '验证通过',
+          startText: '滑动开始服务',
+          successColor: '#72c13f',
+          btnText: '开始'
+        }
+      }
     },
-    mounted() {
-        const systemInfo = uni.getSystemInfoSync()
-        this.screenWidth = systemInfo.screenWidth
+  },
+  data() {
+    return {
+      x: 0,
+      oldx: 0,
+      success: false, //是否验证成功
+      verification: 0, //验证次数
+      isDisable: this.disabled,
+      screenWidth: 0,
+      leftArrows: [
+        { opacity: 0.4, scale: 0.8 },
+        { opacity: 0.4, scale: 0.8 },
+        { opacity: 0.4, scale: 0.8 }
+      ],
+      rightArrows: [
+        { opacity: 0.4, scale: 0.8 },
+        { opacity: 0.4, scale: 0.8 },
+        { opacity: 0.4, scale: 0.8 }
+      ],
+      arrowAnimationTimer: null
+    };
+  },
+  computed: {
+    sliderStyle() {
+      if (this.success) {
+        // 成功状态下根据按钮类型显示不同颜色,然后去使用相同的渐变和阴影效果
+        return this.btnType === 'upload' 
+          ? 'background: linear-gradient(134deg, #FFD4CB 15%, #FF6E51 79%); box-shadow: 4rpx 4rpx 8rpx 2rpx rgba(0, 0, 0, 0.25), inset 4rpx 4rpx 4rpx 4rpx rgba(193, 193, 193, 0.25);' 
+          : 'background: linear-gradient(134deg, #DAFFCB 15%, #22C55D 79%); box-shadow: 4rpx 4rpx 8rpx 2rpx rgba(0, 0, 0, 0.25), inset 4rpx 4rpx 4rpx 4rpx rgba(193, 193, 193, 0.25);';
+      }
+
+      if (this.btnType === 'upload') {
+        return 'background: linear-gradient(134deg, #FFD4CB 15%, #FF6E51 79%); box-shadow: 4rpx 4rpx 8rpx 2rpx rgba(0, 0, 0, 0.25), inset 4rpx 4rpx 4rpx 4rpx rgba(193, 193, 193, 0.25);';
+      } else {
+        return 'background: linear-gradient(134deg, #DAFFCB 15%, #22C55D 79%); box-shadow: 4rpx 4rpx 8rpx 2rpx rgba(0, 0, 0, 0.25), inset 4rpx 4rpx 4rpx 4rpx rgba(193, 193, 193, 0.25);';
+      }
     },
-    methods: {
-        onMove(e) {
-            this.oldx = e.detail.x
-        },
-        touchend() {
-            if (this.success || (this.oldx < 1 && this.oldx != 0.1)) return
-            this.x = this.oldx
-            var promptW = 0
-            var onTrackW = 0
-            uni.createSelectorQuery().in(this).select(".slider-prompt").boundingClientRect(data => {
-                if (data.width > 0) {
-                    promptW = data.width
-                    uni.createSelectorQuery().in(this).select(".movable-btn").boundingClientRect(data => {
-                        if (data.width > 0) {
-                            onTrackW = data.width
-                            if (this.oldx != 0.1) this.verification++
-                            if (this.oldx > (promptW - onTrackW - this.offset)) {
-                                this.success = true
-                                this.isDisable = true
-                                this.verificationSuccess(true)
-                            } else {
-                                this.$nextTick(() => {
-                                    this.x = 0
-                                    this.oldx = 0
-                                })
-                                this.verificationSuccess(false)
-                            }
-                        }
-                    }).exec()
-                }
-            }).exec()
-        },
-        verificationSuccess(state) {
-            let obj = {
-                state: state,
-                verification: this.verification
+    arrowColor() {
+      return this.btnType === 'upload' ? '#FF6E51' : '#22C55D';
+    }
+  },
+  mounted() {
+    const systemInfo = uni.getSystemInfoSync()
+    this.screenWidth = systemInfo.screenWidth
+
+    if (this.btnType === 'upload') {
+      this.sliderText.btnText = '上传照片';
+      this.sliderText.startText = '滑动结束服务';
+    } else {
+      this.sliderText.btnText = '开始';
+      this.sliderText.startText = '滑动开始服务';
+    }
+    
+    // 启动箭头动画
+    this.startArrowAnimation();
+  },
+  methods: {
+    onMove(e) {
+      this.oldx = e.detail.x
+      // 更新背景的滑动动画
+      const percent = Math.min(e.detail.x / (this.screenWidth - 152), 1) // 152为按钮宽度
+      if (percent > 0.9) {
+        this.$emit('nearSuccess', true)
+      }
+    },
+    touchend() {
+      if (this.success || (this.oldx < 1 && this.oldx != 0.1)) return
+      this.x = this.oldx
+      var promptW = 0
+      var onTrackW = 0
+      uni.createSelectorQuery().in(this).select(".slider-prompt").boundingClientRect(data => {
+        if (data.width > 0) {
+          promptW = data.width
+          uni.createSelectorQuery().in(this).select(".movable-btn").boundingClientRect(data => {
+            if (data.width > 0) {
+              onTrackW = data.width
+              if (this.oldx != 0.1) this.verification++
+              if (this.oldx > (promptW - onTrackW - this.offset)) {
+                this.success = true
+                this.isDisable = true
+                this.verificationSuccess(true)
+              } else {
+                this.$nextTick(() => {
+                  this.x = 0
+                  this.oldx = 0
+                })
+                this.verificationSuccess(false)
+              }
             }
-            this.$emit("change", obj)
-        },
-        //重置初始化状态
-        initialization() {
-            this.x = 0
-            this.oldx = 0.1
-            this.verification = 0
-            this.success = false
-            this.isDisable = false
-            this.touchend()
+          }).exec()
+        }
+      }).exec()
+    },
+    // 箭头动画
+    startArrowAnimation() {
+      if (this.arrowAnimationTimer) {
+        clearInterval(this.arrowAnimationTimer);
+      }
+      
+      let step = 0;
+      this.arrowAnimationTimer = setInterval(() => {
+        if (this.success) {
+          clearInterval(this.arrowAnimationTimer);
+          return;
+        }
+        
+        // 更新左侧箭头动画
+        this.leftArrows.forEach((arrow, index) => {
+          const delay = index * 3;
+          const phase = (step + delay) % 15;
+          
+          if (phase < 7) {
+            arrow.opacity = 0.4 + (phase / 7) * 0.6;
+            arrow.scale = 0.8 + (phase / 7) * 0.4;
+          } else {
+            arrow.opacity = 1 - ((phase - 7) / 8) * 0.6;
+            arrow.scale = 1.2 - ((phase - 7) / 8) * 0.4;
+          }
+        });
+        
+        // 更新右侧箭头动画
+        this.rightArrows.forEach((arrow, index) => {
+          const delay = (2 - index) * 3;
+          const phase = (step + delay) % 15;
+          
+          if (phase < 7) {
+            arrow.opacity = 0.4 + (phase / 7) * 0.6;
+            arrow.scale = 0.8 + (phase / 7) * 0.4;
+          } else {
+            arrow.opacity = 1 - ((phase - 7) / 8) * 0.6;
+            arrow.scale = 1.2 - ((phase - 7) / 8) * 0.4;
+          }
+        });
+        
+        step = (step + 1) % 15;
+      }, 100);
+    },
+    verificationSuccess(state) {
+      let obj = {
+        state: state,
+        verification: this.verification
+      }
+      this.$emit("change", obj)
+      
+      if (state) {
+        // 成功后停止动画
+        if (this.arrowAnimationTimer) {
+          clearInterval(this.arrowAnimationTimer);
+          this.arrowAnimationTimer = null;
         }
+      }
+    },
+    //重置初始化状态
+    initialization() {
+      this.x = 0
+      this.oldx = 0.1
+      this.verification = 0
+      this.success = false
+      this.isDisable = false
+      this.startArrowAnimation();  // 重新启动动画
+      this.touchend()
     }
+  }
 }
 </script>
 
 <style scoped>
 .slider-verify {
-    position: relative;
-    width: 100%;
-    height: 100rpx;
-    overflow: hidden;
+  position: relative;
+  width: 100%;
+  height: 100rpx;
+  overflow: hidden;
+  border-radius: 50rpx;
 }
 
 .slider-prompt {
-    width: 100%;
-    height: 100%;
-    position: absolute;
-    left: 0;
-    top: 0;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    font-size: 32rpx;
-    z-index: 99;
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 32rpx;
+  z-index: 99;
 }
 
 .slider-bg {
-    width: 100%;
-    height: 100%;
-    position: absolute;
-    top: 0;
-    left: 0;
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  left: 0;
+  transition: transform 0.3s ease-out;
 }
 
 .slider-area {
-    position: absolute;
-    top: 0;
-    left: 0;
-    height: 100%;
-    width: 100%;
-    z-index: 999;
+  position: absolute;
+  top: 0;
+  left: 0;
+  height: 100%;
+  width: 100%;
+  z-index: 999;
 }
 
 .movable-btn {
-    width: 150rpx;
-    height: 100%;
-    border: solid 1px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    font-size: 17px;
-    color: #fff;
-    /* width: 100rpx;
-    height: 100%;
-    box-sizing: border-box;
-    background-color: #FFFFFF;
-    border: solid 1px;
-    background-image: url(/static/img/go-right.png);
-    background-position: center;
-    background-size: 34rpx auto;
-    background-repeat: no-repeat;
-    display: flex;
-    align-content: center;
-    justify-content: center; */
+  width: 152rpx;
+  height: 100rpx;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 32rpx;
+  color: #fff;
+  font-weight: bold;
+  border-radius: 50rpx;
+  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+  animation: pulse 2s infinite;
 }
 
 .movable-success {
-    /* border: solid 1px;
-    background-image: url(/static/img/success.png);
-    background-size: 40rpx auto; */
+  transition: all 0.3s ease;
+  animation: none;
+}
+
+.arrow-group {
+  display: flex;
+  align-items: center;
+}
+
+.arrow-group.left {
+  margin-right: 24rpx;
+}
+
+.arrow-group.right {
+  margin-left: 24rpx;
+}
+
+.arrow {
+  font-size: 32rpx;
+  margin: 0 4rpx;
+  font-weight: bold;
+  transition: all 0.1s ease;
+}
+
+.arrow-group.left .arrow-img:nth-child(1) {
+  animation-delay: 0s;
+}
+
+.arrow-group.left .arrow-img:nth-child(2) {
+  animation-delay: 0.2s;
+}
+
+.arrow-group.left .arrow-img:nth-child(3) {
+  animation-delay: 0.4s;
+}
+
+.arrow-group.right .arrow-img:nth-child(1) {
+  animation-delay: 0.4s;
+}
+
+.arrow-group.right .arrow-img:nth-child(2) {
+  animation-delay: 0.2s;
+}
+
+.arrow-group.right .arrow-img:nth-child(3) {
+  animation-delay: 0s;
+}
+
+@keyframes breathe {
+  0% {
+    opacity: 0.4;
+    transform: scale(0.8) translateX(0);
+  }
+  50% {
+    opacity: 1;
+    transform: scale(1.2) translateX(0);
+  }
+  100% {
+    opacity: 0.4;
+    transform: scale(0.8) translateX(0);
+  }
+}
+
+@keyframes pulse {
+  0% {
+    box-shadow: 0 0 0 0 rgba(34, 197, 93, 0.4);
+  }
+  70% {
+    box-shadow: 0 0 0 10rpx rgba(34, 197, 93, 0);
+  }
+  100% {
+    box-shadow: 0 0 0 0 rgba(34, 197, 93, 0);
+  }
+}
+
+.go-right {
+  display: none; 
 }
 </style>

+ 5 - 5
pages_classify/pages/handle/index.vue

@@ -15,9 +15,9 @@
               <view class="user-id" style="display: flex">服务类别:{{ detaile.businessTireName }}</view>
             </view>
           </view>
-          <view class="user-phone" @click="onPhone(detaile.clientPhoneNumber)">
+          <!-- <view class="user-phone" @click="onPhone(detaile.clientPhoneNumber)">
             <up-icon name="phone" color="#fff" size="25"></up-icon>
-          </view>
+          </view> -->
         </view>
 
         <view class="handle-adress">
@@ -43,7 +43,7 @@
       <view class="handle-start" v-if="orderStatus && detaile.serviceStartTime && dateData">
         服务已开始:<text class="handle-time">{{ dateData }}</text>
       </view>
-      <Slide ref="verify" @change="change" :sliderText="slideData" />
+      <Slide ref="verify" @change="change" :sliderText="slideData" :btnType="orderStatus ? 'upload' : 'start'" />
     </view>
   </view>
 </template>
@@ -154,14 +154,14 @@ const slideData = computed(() => {
   if (orderStatus.value) {
     return {
       successText: '服务已完成',
-      startText: '拖动滑块结束服务',
+      startText: '滑动结束服务',
       successColor: '#f64a1f',
       btnText: '上传照片',
     }
   }
   return {
     successText: '服务已开始',
-    startText: '拖动滑块开始服务',
+    startText: '滑动开始服务',
     successColor: '#72c13f',
     btnText: '开始',
   }

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

@@ -6,21 +6,8 @@
         <Detiles></Detiles>
       </view>
 
-      <!-- 页面背景整体定位 -->
-      <view class="service-description-position">
-
-        <!-- 价格服务介绍 -->
-        <view class="service-description-container">
-          <view class="service-text">{{ listData.businessDescribe }}</view>
-          <view class="service-price-tag">¥{{ listData.businessPrice }}</view>
-        </view>
-
-      </view>
-
-
     <!-- 页面背景整体定位 -->
     <view class="service-description-position">
-
       <!-- 价格服务介绍 -->
       <view class="service-description-container">
         <view class="service-price-top">

+ 56 - 6
pages_home/pages/search/index.vue

@@ -1,8 +1,8 @@
 <template>
   <view class="search-page">
     <!-- 搜索输入框 -->
-    <u-input placeholder="请输入搜索的服务" prefixIcon="search" v-model="value" class="rounded-input"
-      @confirm="handleSearch"></u-input>
+    <u-input placeholder="请输入搜索的服务" prefixIcon="search" v-model="value" class="rounded-input" @confirm="handleSearch"
+      clearable @clear="handleClear"></u-input>
     <!-- 历史记录 -->
     <view class="history-search">
       <view class="history-search-title">历史搜索</view>
@@ -11,6 +11,11 @@
         清空
       </view>
     </view>
+
+    <!-- tab -->
+    <view>
+      <up-tabs :list="list2"></up-tabs>
+    </view>
     <!-- 瀑布流展示区域 -->
     <view class="home-ranking">
       <ServIces :leftList="leftList" :rightList="rightList" :ValueZoneSwiper="ValueZoneSwiper" v-if="userType == 1">
@@ -27,7 +32,7 @@
 <script setup>
 import { ref, reactive, onMounted, watch } from 'vue'
 import { onShow, onReachBottom } from '@dcloudio/uni-app'
-import { volTierName } from '@/api/volunteerDetailsApi/details.js'
+import { volTierName, volBusinessTypeList } from '@/api/volunteerDetailsApi/details.js'
 import RankingList from '@/pages/common/rankingList/index.vue'
 import ServIces from '@/components/Services/services.vue'
 import store from '@/store'
@@ -38,6 +43,9 @@ const value = ref('')
 const rightList = ref([])
 const leftList = ref([])
 const ValueZoneSwiper = ref([''])
+
+const list2 = reactive([]);  
+
 // 用户类型
 const userType = uni.getStorageSync('userType') || 1; //读取本地存储
 // 添加搜索定时器引用
@@ -49,7 +57,8 @@ const pages = ref({
   pageSize: 10,
   total: 0,
   serviceCategory: '',
-  businessTierName: '' // 添加搜索关键词参数
+  businessTierName: '', // 添加搜索关键词参数
+  businessManagementId: 0
 })
 
 // 加载更多状态配置
@@ -105,7 +114,7 @@ const getList = async () => {
       serviceCategory: pages.value.serviceCategory || '',
       businessManagementId: 0,
       // API接口使用的模糊搜索参数
-      businessTierName: value.value, // 业务名称搜索参数
+      businessTierName: value.value, // 名称搜索参数
 
       // 地址相关参数
       provinceName: cityCode.data[0], // 省
@@ -118,10 +127,40 @@ const getList = async () => {
       longitude,
     }
 
-    console.log('搜索参数:', params); // 添加日志查看参数
+    const paramstyle = {
+      businessTierName: value.value, // 名称搜索参数
+      businessManagementId: 0,
+    }
+    console.log('businessManagementId 类型:', typeof params.businessManagementId);
+    console.log('businessManagementId 值:', params.businessManagementId);
+    console.log('paramstyle 对象:', paramstyle);
+    console.log('paramstyle中的businessManagementId:', paramstyle.businessManagementId);
+    // 调用API前的最终参数检查
+    console.log('发送前的最终参数(JSON):', JSON.stringify(params));
+    console.log('发送前的style参数(JSON):', JSON.stringify(paramstyle));
 
     // 调用API获取数据
     const res = await volTierName(params)
+    const res1 = await volBusinessTypeList(paramstyle)
+    if (res1 && res1.data) {
+      // 清空原有数据
+      list2.splice(0, list2.length)
+      
+      // 添加全部选项
+      list2.push({
+        name: '全部',
+        value: '0'
+      })
+      
+      // 转换API返回的数据为up-tabs需要的格式
+      res1.data.forEach(item => {
+        list2.push({
+          name: item.businessTierName,
+        })
+      })
+      
+      console.log('转换后的Tabs数据:', list2)
+    }
 
     if (!res || !res.rows) {
       return
@@ -195,6 +234,17 @@ watch(value, (newVal) => {
     getList()
   }, 500)
 })
+
+/**
+ * 处理清除搜索内容
+ */
+const handleClear = () => {
+  value.value = ''
+  // 重置页码
+  pages.value.current = 1
+  // 清空后显示全部数据
+  getList()
+}
 </script>
 
 <style scoped lang="scss">

二进制
static/img/绿箭头.png