瀏覽代碼

测试提交2

743180155@qq.com 11 月之前
父節點
當前提交
add6d0bf0b

+ 269 - 0
src/pages/tabbar/components/communityPop.vue

@@ -0,0 +1,269 @@
+<template>
+  <view class="container">
+    <u-sticky>
+      <view class="pop-top">
+        <view class="top-box">
+          <view class="top-black-box"></view>
+        </view>
+        <view class="top-title"> {{ total }}条回复 </view>
+      </view>
+    </u-sticky>
+
+    <view class="center-box">
+      <view class="center-item" v-for="(item, index) of init_list" :key="index">
+        <view class="item-top">
+          <view class="top-left">
+            <view class="top-img">
+              <image :src="item.userDTO.avatar" class="img" mode=""></image>
+            </view>
+            <view class="top-text">
+              <view class="text-title">{{ item.userDTO.nickname }}</view>
+              <view class="text-address"> {{ item.distanceTime }} </view>
+            </view>
+          </view>
+          <view class="top-right">
+            <u-icon
+              :name="item.clickStatus == 0 ? 'heart' : 'heart-fill'"
+              size="22"
+              @click="handlerFocus(item)"
+            ></u-icon>
+          </view>
+        </view>
+
+        <view class="item-text"> {{ item.content }} </view>
+      </view>
+    </view>
+
+    <!-- <empty v-if="total == 0" /> -->
+
+    <view class="bottom-box">
+      <view class="bottom-item">
+        <view class="item-left">
+          <u--input
+            placeholder="写回复"
+            border="surround"
+            v-model="content"
+            shape="circle"
+            customStyle="background-color:#F2F2F2"
+          ></u--input>
+        </view>
+        <view class="item-right">
+          <button @click="handlerPopPublishBtn" class="btn">发布</button>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+import { addClientComment, clientCommentList } from '@/api/client/message.js';
+import { addEvaulateRecords } from '@/api/client/community.js';
+// import empty from '@/components/empty/index.vue';
+import { GetDateToNewData } from "@/utils/tools.js"
+export default {
+  // components: { empty },
+  data() {
+    return {
+      content: '',
+      init_list: [],
+      total: 0,
+    };
+  },
+  props: ['dynamicId', 'dynamicUserId'],
+  watch: {
+    dynamicId(newValue) {
+      if (newValue != null) {
+        this.handlerInitList();
+      }
+    },
+  },
+  methods: {
+    // 初始化评论列表
+    handlerInitList() {
+      let params = {
+        dynamicId: this.dynamicId,
+        parentId: 0,
+        userId: this.dynamicUserId,
+      };
+      clientCommentList(params).then(res => {
+		  res.data.records.map(rs=>{
+			  let time = GetDateToNewData(rs.createTime)
+			  this.$set(rs,'distanceTime',time)
+		  })
+        this.init_list = res.data.records;
+        this.total = res.data.total;
+      });
+    },
+    // 发布评论
+    handlerPopPublishBtn() {
+      let params = {
+        dynamicId: this.dynamicId,
+		targetUserId:this.dynamicUserId,
+        parentId: 0,
+        content: this.content,
+        status: 0,
+      };
+      addClientComment(params).then(res => {
+        if (res.code === 'OK') {
+          uni.showToast({
+            title: '发布成功',
+            icon: 'none',
+          });
+          this.content = '';
+          this.handlerInitList();
+          this.$emit('uploadComment');
+        }
+      });
+    },
+    // 关注按钮
+    handlerFocus(item) {
+      let params = {
+        dynamicStatusType: 'GOOD', // 操作类型:1-点赞;2-踩 允许值: GOOD, BAD
+        recordType: 'COMMENT', // 内容类型:1-动态;2-评论/回复 允许值: DYNAMIC, COMMENT, USER
+        actionType: item.clickStatus == 0 ? 'ADD' : 'CANCEL', // 点击类型:1-点赞/踩;2-取消赞/取消踩   允许值: ADD, CANCEL
+        contentId: item.id,
+        targetUserId: item.userId,
+      };
+      addEvaulateRecords(params).then(res => {
+        if (res.code === 'OK') {
+          uni.showToast({
+            title: '关注成功',
+            icon: 'none',
+          });
+          this.handlerInitList();
+        } else {
+          uni.showToast({
+            title: res.msg,
+            icon: 'none',
+          });
+          return;
+        }
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.container {
+  height: 70vh;
+  overflow-y: auto;
+  box-sizing: border-box;
+  padding-bottom: 120rpx;
+
+  .pop-top {
+    background-color: #fff;
+    border-radius: 40rpx;
+    padding: 20rpx 0;
+  }
+
+  .top-box {
+    display: flex;
+    justify-content: center;
+
+    .top-black-box {
+      width: 10%;
+      height: 10rpx;
+      background-color: #000;
+      border-radius: 10%;
+    }
+  }
+
+  .top-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    color: #000;
+    text-align: center;
+    margin-top: 20rpx;
+    letter-spacing: 2rpx;
+  }
+
+  .center-box {
+    margin-bottom: 20rpx;
+    padding: 0 20rpx;
+
+    .center-item {
+      margin-bottom: 40rpx;
+      border-radius: 20rpx;
+
+      .item-top {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+
+        .top-left {
+          display: flex;
+          align-items: center;
+
+          .top-img {
+            .img {
+              width: 80rpx;
+              height: 80rpx;
+              border-radius: 50%;
+            }
+          }
+
+          .top-text {
+            display: flex;
+            flex-direction: column;
+            justify-content: space-around;
+            margin-left: 10rpx;
+
+            .text-title {
+              font-weight: bold;
+              font-size: 32rpx;
+              color: #000;
+            }
+
+            .text-address {
+              color: #8f8f8f;
+              font-size: 24rpx;
+            }
+          }
+        }
+      }
+
+      .item-text {
+        margin-top: 20rpx;
+        padding: 0 40rpx;
+      }
+    }
+  }
+
+  .bottom-box {
+    position: absolute;
+    bottom: 0;
+    background-color: #fff;
+    width: 100%;
+    height: 150rpx;
+
+    .bottom-item {
+      display: flex;
+      justify-content: space-around;
+      padding: 10rpx 20rpx 0;
+      box-sizing: border-box;
+      align-items: center;
+
+      .item-left {
+        width: 60%;
+        height: 70rpx;
+      }
+
+      .item-right {
+        width: 30%;
+        padding: 20rpx;
+
+        .btn {
+          border-radius: 20rpx;
+          text-align: center;
+          color: #fff;
+          background: linear-gradient(to right, #e8cbc0, #636fa4);
+          height: 70rpx;
+          font-size: 28rpx;
+          line-height: 70rpx;
+        }
+      }
+    }
+  }
+}
+</style>

+ 434 - 0
src/pagesHome/category/categoryStoreList.vue

@@ -0,0 +1,434 @@
+<template>
+  <view class="container" @click="filterShow = false">
+    <view class="top-box">
+      <view class="search-box">
+        <view class="search-left">
+          <u-search placeholder="请输入搜索内容" :showAction="false" v-model="sellerListParams.keyword" />
+        </view>
+        <view class="search-right" @click='handlerSearch'>搜索</view>
+      </view>
+      <view class="filter-box">
+        <view class="filter-item">
+   <!--       <view class="fiter1">
+            <u-icon name="map"></u-icon>
+            <span class="filter-l">贵阳市青少年人才社区</span>
+            <u-icon name="arrow-down-fill"></u-icon>
+          </view> -->
+          <view class="fiter2" @tap.stop="handlerSelectAllFilter(2)">
+            <span>{{ sortCondition }}</span>
+            <u-icon name="arrow-down-fill"></u-icon>
+          </view>
+          <view class="fiter1" @tap.stop="handlerSelectMenu(1)">
+            <span>筛选</span>
+            <u-icon name="arrow-down-fill"></u-icon>
+          </view>
+        </view>
+        <view class="filter-drapdown" v-show="filterShow">
+          <view class="filter1" v-show="filterType == 1">
+            <view class="scroll-box">
+              <scroll-view :scroll-top="scrollTop" scroll-y="true" class="filter-menu-left scroll-Y"
+                @scrolltoupper="upper" @scrolltolower="lower" @scroll="scroll">
+                <view id="demo1" class="scroll-view-item uni-bg-red menu-item"
+                  :class="current == index ? 'act-left-menu' : ''" v-for="(item, index) of menuList" :key="index"
+                  @click.stop="handlerSelectLMenu(item, index)">{{ item.name }}
+                </view>
+              </scroll-view>
+              <scroll-view :scroll-top="scrollTop" scroll-y="true" class="filter-menu-right scroll-Y"
+                @scrolltoupper="upper" @scrolltolower="lower" @scroll="scroll">
+                <view id="demo1" class="scroll-view-item uni-bg-red" v-for="item of 15" :key="item">
+                  <view class="menu-right-title">洗车</view>
+                  <view class="menu-right-contentbox">
+                    <span class="menu-item" v-for="item of 7" :key="item">测试</span>
+                  </view>
+                </view>
+              </scroll-view>
+            </view>
+          </view>
+          <view class="filter2" v-show="filterType == 2">
+            <view @tap="sellerListFillter(1)">离我最近</view>
+            <view @tap="sellerListFillter(2)">好评优先</view>
+            <view @tap="sellerListFillter(3)">销量优先</view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <view class="content-box">
+      <view class="content-item" v-for="(item, index) in sellerList" :key="index" @tap="goSellerDetail(item.id)">
+        <view class="item-left">
+          <image class="img" :src="item.logo" mode="aspectFit"></image>
+          <!-- <image class="img" :src="error || !loaded ? 'https://cdn.uviewui.com/uview/album/10.jpg' : item.logo"
+            mode="scaleToFill"></image> -->
+        </view>
+        <view class="item-right">
+          <view>
+            <view class="item-title">
+              <view class="tag">常去</view>
+              <view class="title">{{ `${item.name}(${item.address})` }}</view>
+            </view>
+            <view class="str-box">
+              <view class="srt-left">
+                <u-rate activeColor="#fc8400" :value="item.score" readonly></u-rate>
+                <text>{{ item.score }}</text>
+              </view>
+              <view class="border"></view>
+              <!-- <view class="srt-right">{{ item.sale }}单</view> -->
+              <view class="srt-right"></view>
+            </view>
+          </view>
+
+          <view class="bottom-textbox">
+            <view class="bottom-left">宝安中心区美容洗车</view>
+            <view class="bottom-right">{{ (item.distance / 1000).toFixed(2) }}KM</view>
+          </view>
+        </view>
+      </view>
+      <u-empty v-if="sellerList.length == 0" mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png"></u-empty>
+    </view>
+  </view>
+</template>
+
+<script>
+  import { getSellerList } from '@/api/client/business.js';
+  import { getCurrentLocation } from '@/api/client/home.js';
+  import { mapGetters } from 'vuex';
+  export default {
+    data() {
+      return {
+        filterShow: false,
+        filterType: 0,
+        sortCondition: '综合排序',
+        current: 0,
+        menuList: [{
+            name: '汽车',
+          },
+          {
+            name: '汽车2',
+          },
+          {
+            name: '汽车3',
+          },
+          {
+            name: '汽车4',
+          },
+        ],
+        sellerList: [],
+        sellerListParams: {
+          longitude: '',
+          latitude: '',
+          sort: 'SYNTHESE',
+          size: 10,
+          region: '', //地区编码
+          keyword: '', //关键字
+          categoryId: '', //分类ID
+        },
+      };
+    },
+    onLoad(option) {
+      if(option.id){
+        this.sellerListParams.categoryId = option.id;
+      }
+	  if(option.keyword){
+		  this.sellerListParams.keyword = option.keyword;
+	  }
+    },
+	mounted() {
+	  let { latitude , longitude , region } = this.location
+	  this.sellerListParams.latitude = latitude
+	  this.sellerListParams.longitude = longitude
+	  this.sellerListParams.region = region
+	  this.getData();
+	},
+	computed:{
+		  ...mapGetters(['location'])
+	},
+    methods: {
+      // 点击综合排序
+      handlerSelectAllFilter(e) {
+        this.filterShow = true;
+        this.filterType = 2;
+      },
+      // 排序条件
+      sellerListFillter(e) {
+        switch (e) {
+          case 1:
+            this.sortCondition = '离我最近';
+            this.sellerListParams.sort = 'NEAREST';
+            break;
+          case 2:
+            this.sortCondition = '好评优先';
+            this.sellerListParams.sort = 'FAVORITE';
+            break;
+          case 3:
+            this.sortCondition = '销量优先';
+            this.sellerListParams.sort = 'BESTSELLING';
+            break;
+          default:
+            break;
+        }
+        this.getData();
+      },
+      // 获取初始化列表
+      getData() {
+        getSellerList(this.sellerListParams)
+          .then(res => {
+            this.sellerList = res.data;
+          })
+          .catch(err => {});
+      },
+      // 点击进入详情
+      goSellerDetail(id) {
+        uni.navigateTo({
+          url: `/pagesHome/category/categoryStoreList?id=${id}`,
+        });
+      },
+      //
+      handlerSelectMenu(e) {
+		  // uni.navigateTo({
+		  // 	url:'/pages/client/clientPackage/category'
+		  // })
+        // this.filterShow = true;
+        // this.filterType = 1;
+      },
+      // 选择左侧菜单
+      handlerSelectLMenu(item, index) {
+        this.current = index;
+      },
+      scroll() {},
+      lower() {},
+      upper() {},
+      // 搜索
+      handlerSearch(){
+        this.getData()
+      }
+    },
+  };
+</script>
+
+<style lang="scss" scoped>
+  .container {
+    min-height: 100vh;
+    background-color: #efefef;
+
+    .top-box {
+      width: 100%;
+      background-color: #fff;
+      padding: 10rpx 20rpx;
+      box-sizing: border-box;
+
+      .search-box {
+        display: flex;
+        justify-content: space-around;
+        align-items: center;
+
+        .search-left {
+          width: 80%;
+        }
+
+        .search-right {
+          text-align: center;
+        }
+      }
+
+      .filter-box {
+        margin-top: 20rpx;
+
+        .filter-item {
+          display: flex;
+          justify-content: space-between;
+
+          .fiter1,
+          .fiter2 {
+            display: flex;
+            align-items: center;
+          }
+
+          .filter-l {
+            width: 200rpx;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
+
+          .fiter1 {
+            color: #808080;
+            font-size: 24rpx;
+          }
+
+          .fiter2 {}
+        }
+
+        .filter-drapdown {
+          position: fixed;
+          left: 0;
+          width: 100%;
+          background-color: #fff;
+          // height: 300rpx;
+          z-index: 999;
+          box-shadow: 0 10rpx 20rpx -5rpx rgba(0, 0, 0, 0.2);
+
+          .filter1 {
+            .scroll-box {
+              display: flex;
+              max-height: 1200rpx;
+
+              .filter-menu-left {
+                width: 30%;
+                background-color: #ebebeb;
+                overflow-y: scroll;
+
+                .menu-item {
+                  width: 100%;
+                  height: 100rpx;
+                  text-align: center;
+                  line-height: 100rpx;
+                  font-size: 30rpx;
+                  background-color: #ebebeb;
+                  color: #5a5a5a;
+                }
+
+                .act-left-menu {
+                  background-color: #fff;
+                  color: #5992bb;
+                  border-right: 8rpx solid #5992bb !important;
+                }
+              }
+
+              .filter-menu-right {
+                background-color: #fff;
+                padding: 10rpx 20rpx;
+                box-sizing: border-box;
+                width: 70%;
+                overflow-y: scroll;
+
+                .menu-right-title {
+                  font-size: 30rpx;
+                  color: #000;
+                  margin-bottom: 10rpx;
+                }
+
+                .menu-right-contentbox {
+                  padding: 0 0 0 30rpx;
+                  display: flex;
+                  justify-content: left;
+                  flex-wrap: wrap;
+
+                  .menu-item {
+                    // width: 100rpx;
+                    padding: 0 20rpx;
+                    height: 40rpx;
+                    background-color: #cccccc;
+                    color: #000;
+                    text-align: center;
+                    line-height: 40rpx;
+                    margin: 10rpx 20rpx;
+                  }
+                }
+              }
+            }
+          }
+
+          .filter2 {
+            padding: 20rpx 50rpx;
+            box-sizing: border-box;
+
+            view {
+              margin: 30rpx 0;
+            }
+          }
+        }
+      }
+    }
+
+    .content-box {
+      width: 100%;
+
+      .content-item {
+        background-color: #fff;
+        padding: 10rpx 20rpx;
+        box-sizing: border-box;
+        margin: 10rpx 0;
+        display: flex;
+
+        .item-left {
+          margin-right: 10rpx;
+
+          .img {
+            width: 200rpx;
+            height: 200rpx;
+            border-radius: 10rpx;
+          }
+        }
+
+        .item-right {
+          height: 200rpx;
+          align-content: space-between;
+
+          .item-title {
+            display: flex;
+            align-items: center;
+
+            .tag {
+              width: 80rpx;
+              height: 46rpx;
+              line-height: 35rpx;
+              padding: 4rpx;
+              font-size: 22rpx;
+              box-sizing: border-box;
+              background-color: #f6e7d4;
+              color: #f99a47;
+              border: 2rpx solid #f99a47;
+              text-align: center;
+              // align-items: center;
+              margin-right: 10rpx;
+            }
+
+            .title {
+              width: 85%;
+              font-size: 30rpx;
+              color: #000;
+              font-weight: bold;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              display: -webkit-box;
+              -webkit-line-clamp: 2;
+              -webkit-box-orient: vertical;
+            }
+          }
+
+          .str-box {
+            display: flex;
+            margin-top: 10rpx;
+
+            .srt-left {
+              display: flex;
+              color: #fc8400;
+            }
+
+            .border {
+              border-left: 2rpx solid #cfcfcf;
+              margin: 0 20rpx;
+            }
+
+            .srt-right {}
+          }
+
+          .bottom-textbox {
+            display: flex;
+            justify-content: space-between;
+            font-size: 26rpx;
+            margin-top: 40rpx;
+
+            .bottom-left {
+              color: #c7c7c7;
+            }
+
+            .bottom-right {
+              color: #000;
+            }
+          }
+        }
+      }
+    }
+  }
+</style>

+ 352 - 0
src/pagesHome/category/index.vue

@@ -0,0 +1,352 @@
+<template>
+  <view class="u-wrap">
+    <view class="u-menu-wrap">
+      <scroll-view
+        scroll-y
+        scroll-with-animation
+        class="u-tab-view menu-scroll-view"
+        :scroll-top="scrollTop"
+        :scroll-into-view="itemId"
+      >
+        <view
+          v-for="(item, index) in left_first_list"
+          :key="index"
+          class="u-tab-item"
+          :class="[current == index ? 'u-tab-item-active' : '']"
+          @tap.stop="handleLeftMenuClick(index)"
+        >
+          <text class="u-line-1">{{ item.name }}</text>
+        </view>
+      </scroll-view>
+
+      <scroll-view
+        :scroll-top="scrollRightTop"
+        scroll-y
+        scroll-with-animation
+        class="right-box"
+        @scroll="rightScroll"
+      >
+        <view class="page-view">
+          <view
+            class="class-item"
+            :id="'item' + index"
+            v-for="(item, index) in left_first_list"
+            :key="index"
+          >
+            <view class="item-title">
+              <text>{{ item.name }}</text>
+            </view>
+            <view class="item-container">
+              <view
+                class="thumb-box"
+                v-for="(child, childIndex) in item.children"
+                :key="childIndex"
+                @click="handleItemClick(child.id, child.name)"
+              >
+                <image
+                  v-if="child.icon != ''"
+                  class="item-menu-image"
+                  :src="child.icon"
+                  mode=""
+                ></image>
+                <view v-else class="item-menu-image row-c" style="background-color: #f4f6f8">
+                  <text style="font-size: 20rpx; color: #d0d0d0">加载失败</text>
+                </view>
+                <view class="item-menu-name">{{ child.name }}</view>
+              </view>
+            </view>
+          </view>
+        </view>
+      </scroll-view>
+    </view>
+  </view>
+</template>
+
+<script>
+// import {
+//   buildTree
+// } from '@/utils/tools.js';
+import { maintainCategories } from '@/api/client/business.js';
+export default {
+  data() {
+    return {
+      scrollTop: 0, //tab标题的滚动条位置
+      oldScrollTop: 0, // tab标题的滚动条旧位置
+      current: 0, // 预设当前项的值
+      menuHeight: 0, // 左边菜单的高度
+      menuItemHeight: 0, // 左边菜单item的高度
+      itemId: '', // 栏目右边scroll-view用于滚动的id
+      cateList: [], // 渲染的数据
+      arr: [], // 储存距离顶部高度的数组
+      scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
+      timer: null, // 定时器
+      left_first_list: [], //左侧一级列表
+    };
+  },
+  onLoad() {
+    // this.cateList = buildTree(this.getCache('categories'));
+  },
+  onReady() {
+    this.getMenuItemTop();
+  },
+  mounted() {
+    // 获取左侧一级列表信息
+    maintainCategories({ merchantId: '', type: 0 }).then(res => {
+      console.log('@@@@res', res);
+      this.left_first_list = res.data;
+    });
+  },
+  methods: {
+    /**
+     * 获取一个目标元素的高度
+     * @elClass 元素的类名
+     * @dataVal 储存高度的对象
+     */
+    getElRect(elClass, dataVal) {
+      new Promise((resolve, reject) => {
+        const query = uni.createSelectorQuery().in(this);
+        query
+          .select('.' + elClass)
+          .fields(
+            {
+              size: true,
+            },
+            res => {
+              // 如果节点尚未生成,res值为null,循环调用执行
+              if (!res) {
+                setTimeout(() => {
+                  this.getElRect(elClass);
+                }, 10);
+                return;
+              }
+              this[dataVal] = res.height;
+              resolve();
+            },
+          )
+          .exec();
+      });
+    },
+    /**
+     * 获取右边菜单每个item到顶部的距离
+     * 储存到 arr 数组里面用于后面滚动判断
+     */
+    getMenuItemTop() {
+      new Promise(resolve => {
+        let selectorQuery = uni.createSelectorQuery();
+        selectorQuery
+          .selectAll('.class-item')
+          .boundingClientRect(rects => {
+            // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
+            if (!rects.length) {
+              setTimeout(() => {
+                this.getMenuItemTop();
+              }, 10);
+              return;
+            }
+            rects.forEach(rect => {
+              // 视情况而定,这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
+              // this.arr.push(rect.top - rects[0].top);
+              this.arr.push(rect.top);
+              resolve();
+            });
+          })
+          .exec();
+      });
+    },
+    /**
+     * 观测元素相交状态
+     * 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
+     * 如果跟.right-box底部相交,就动态设置左边栏目的活动状态
+     */
+    async observer() {
+      this.cateList.map((val, index) => {
+        let observer = uni.createIntersectionObserver(this);
+        observer
+          .relativeTo('.right-box', {
+            top: 0,
+          })
+          .observe('#item' + index, res => {
+            if (res.intersectionRatio > 0) {
+              let id = res.id.substring(4);
+              this.leftMenuStatus(id);
+            }
+          });
+      });
+    },
+    /**
+     * 设置左边菜单的滚动状态
+     * @index 传入的 ID
+     */
+    async leftMenuStatus(index) {
+      this.current = index;
+      // 如果为0,意味着尚未初始化
+      if (this.menuHeight == 0 || this.menuItemHeight == 0) {
+        await this.getElRect('menu-scroll-view', 'menuHeight');
+        await this.getElRect('u-tab-item', 'menuItemHeight');
+      }
+      // 将菜单活动item垂直居中
+      this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
+    },
+    /**
+     * 点击左边的栏目切换
+     * @index 传入的 ID
+     */
+    async handleLeftMenuClick(index) {
+      if (this.arr.length == 0) {
+        await this.getMenuItemTop();
+      }
+      if (index == this.current) return;
+      this.scrollRightTop = this.oldScrollTop;
+      this.$nextTick(function () {
+        this.scrollRightTop = this.arr[index];
+        this.current = index;
+        this.leftMenuStatus(index);
+      });
+    },
+    /**
+     * 右边菜单滚动
+     * 如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可
+     */
+    async rightScroll(e) {
+      this.oldScrollTop = e.detail.scrollTop;
+      if (this.arr.length == 0) {
+        await this.getMenuItemTop();
+      }
+      if (this.timer) return;
+      if (!this.menuHeight) {
+        await this.getElRect('menu-scroll-view', 'menuHeight');
+      }
+      setTimeout(() => {
+        // 节流
+        this.timer = null;
+        // scrollHeight为右边菜单垂直中点位置
+        // let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
+        // scrollHeight为右边菜单头部位置
+        let scrollHeight = e.detail.scrollTop + 20;
+        for (let i = 0; i < this.arr.length; i++) {
+          let height1 = this.arr[i];
+          let height2 = this.arr[i + 1];
+          if (!height2 || (scrollHeight >= height1 && scrollHeight < height2)) {
+            this.leftMenuStatus(i);
+            return;
+          }
+        }
+      }, 10);
+    },
+    handleItemClick(id, name) {
+      this.$Router.push(`/pagesHome/category/categoryStoreList?id=${id}`);
+    },
+  },
+};
+</script>
+
+<style scoped>
+.u-wrap {
+  /* #ifdef H5 */
+  height: calc(100vh - var(--window-top));
+  /* #endif */
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+}
+
+.u-search-box {
+  padding: 18rpx 30rpx;
+}
+
+.u-menu-wrap {
+  flex: 1;
+  display: flex;
+  overflow: hidden;
+}
+
+.u-tab-view {
+  width: 200rpx;
+  height: 100%;
+}
+
+.u-tab-item {
+  height: 110rpx;
+  background: #f6f6f6;
+  box-sizing: border-box;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 26rpx;
+  color: #444;
+  font-weight: 400;
+  line-height: 1;
+}
+
+.u-tab-item-active {
+  position: relative;
+  color: #06a446;
+  font-size: 30rpx;
+  font-weight: 500;
+  background: #d6ffe7;
+}
+
+.u-tab-item-active::before {
+  content: '';
+  position: absolute;
+  border-left: 4px solid #06a446;
+  height: 52rpx;
+  left: 0;
+  top: 29rpx;
+}
+
+.u-tab-view {
+  height: 100%;
+}
+
+.right-box {
+  background-color: rgb(250, 250, 250);
+}
+
+.page-view {
+  padding: 16rpx;
+}
+
+.class-item {
+  margin-bottom: 30rpx;
+  background-color: #fff;
+  padding: 16rpx;
+  border-radius: 8rpx;
+}
+
+.class-item:last-child {
+  min-height: 100vh;
+}
+
+.item-title {
+  font-size: 26rpx;
+  color: #06a446;
+  font-weight: bold;
+}
+
+.item-menu-name {
+  margin-top: 8rpx;
+  font-weight: normal;
+  font-size: 24rpx;
+  color: #06a446;
+}
+
+.item-container {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.thumb-box {
+  width: 33.333333%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+  margin-top: 20rpx;
+}
+
+.item-menu-image {
+  width: 120rpx;
+  height: 120rpx;
+}
+</style>

+ 263 - 0
src/pagesHome/homeSearch.vue

@@ -0,0 +1,263 @@
+<template>
+  <view class="search">
+    <view class="search-item">
+      <u-search v-model="search_text" :clearabled="true" @custom="handlerSearchBtn" />
+      <!-- <button class="search-btn" @click="handlerSearchBtn">搜索</button> -->
+    </view>
+
+    <!-- 搜索历史 -->
+    <view class="history">
+      <view class="history-top">
+        <hotCom>搜索历史</hotCom>
+        <view class="history-right" @click="handlerAllSearchRecord">
+          <u-icon name="trash" />
+          <text>删除记录</text>
+        </view>
+      </view>
+      <view class="label">
+        <u-tag
+          v-for="(item, index) of search_list"
+          :key="index"
+          :text="item.name"
+          plain
+          closable
+          :show="close2"
+          @close="handlerCloseSearchItem(item, index)"
+          @click="handlerSelctHistItem(item)"
+        />
+      </view>
+    </view>
+    <!-- 热门搜索 -->
+    <view class="history">
+      <view class="history-top">
+        <text class="hotCom">热门搜索</text>
+      </view>
+      <view class="label">
+        <u-tag
+          v-for="(item, index) in popular_search_list"
+          :text="item.name"
+          :key="index"
+          class="label-item"
+          @click="$Router.push(`/pagesHome/marketer/index?id=${item.id}`)"
+        />
+      </view>
+    </view>
+    <u-divider text="猜你喜欢"></u-divider>
+    <!-- 列表 -->
+    <view class="popular-box">
+      <view class="popular-item">
+        <view
+          class="item-box layered"
+          v-for="(item, index) of favourite_list"
+          @click="$Router.push(`/pagesHome/marketer/index?id=${item.id}`)"
+        >
+          <view class="item-left">
+            <image class="img" :src="item.logo"></image>
+          </view>
+          <view class="item-right">
+            <view class="item-title">{{ item.name }}</view>
+            <view class="item-score">
+              <u-rate count="5" :value="item.score" readonly />
+            </view>
+            <view class="item-address"> {{ item.address }} </view>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+import { listHotMerchant, likeMerchant } from '@/api/client/home.js';
+import { mapGetters } from 'vuex';
+export default {
+  data() {
+    return {
+      count: 5,
+      value: 4,
+      close2: true,
+      radios: [
+        {
+          checked: true,
+        },
+      ],
+      checkboxs: [
+        {
+          checked: true,
+        },
+      ],
+      search_text: '', // 搜索text
+      search_list: [], // 搜索列表
+
+      popular_search_list: [], //热门搜索列表
+      favourite_list: [], // 猜你喜欢列表
+    };
+  },
+  computed: {
+    ...mapGetters(['location']),
+  },
+  onShow() {
+    if (uni.getStorageSync('searchItem')) {
+      this.search_list = uni.getStorageSync('searchItem');
+    }
+  },
+  mounted() {
+    this.handlerInitList();
+  },
+  methods: {
+    // 初始化热门搜索 猜你喜欢列表
+    handlerInitList() {
+      listHotMerchant({...this.location}).then(res => {
+        this.popular_search_list = res.data;
+      });
+
+      // 猜你喜欢列表
+      likeMerchant({ ...this.location }).then(res => {
+        this.favourite_list = res.data;
+      });
+    },
+    // 点击搜索按钮
+    handlerSearchBtn() {
+      let params = {
+        name: this.search_text,
+      };
+      this.search_list.push(params);
+      uni.setStorageSync('searchItem', this.search_list);
+      uni.navigateTo({
+        url: `/pages/client/clientPackage/storeList?keyword=${this.search_text}`,
+      });
+    },
+    // 删除搜索记录按钮
+    handlerCloseSearchItem(item, index) {
+      this.search_list.splice(index, 1);
+      uni.setStorageSync('searchItem', this.search_list);
+    },
+    // 点击搜索历史按钮
+    handlerSelctHistItem(item) {
+      this.search_text = item.name;
+      uni.navigateTo({
+        url: `/pages/client/clientPackage/storeList?keyword=${this.search_text}`,
+      });
+    },
+    // 删除所有搜索记录按钮
+    handlerAllSearchRecord() {
+      uni.removeStorageSync('searchItem');
+      this.search_list = [];
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.search {
+  min-height: 100vh;
+  background-color: #fff;
+}
+
+/* 搜索样式 */
+.search-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0 20rpx;
+  height: 80rpx;
+  line-height: 80rpx;
+  background-color: #fff;
+  margin-bottom: 10rpx;
+
+  .search-btn {
+    width: 160rpx;
+    height: 70rpx;
+    font-size: 28rpx;
+    line-height: 70rpx;
+  }
+}
+
+/* 搜索历史样式 */
+.history {
+  padding: 30rpx;
+  margin-bottom: 10rpx;
+
+  .history-top {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 20rpx;
+
+    .history-right {
+      margin-top: 15rpx;
+      display: flex;
+      font-size: 12px;
+    }
+
+    hotCom {
+      font-size: 15px;
+      font-weight: bold;
+      color: #404045;
+    }
+  }
+}
+
+.label {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.label-item {
+  margin-bottom: 20rpx;
+}
+
+.popular-box {
+  padding: 20rpx;
+
+  .item-box {
+    display: flex;
+    margin-bottom: 20rpx;
+    border-radius: 20rpx;
+    padding: 20rpx;
+
+    .item-left {
+      margin-right: 20rpx;
+
+      .img {
+        width: 160rpx;
+        height: 160rpx;
+        border-radius: 20rpx;
+      }
+    }
+
+    .item-right {
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+
+      .item-title {
+        color: #000;
+        font-weight: bold;
+        font-size: 32rpx;
+      }
+
+      .item-address {
+        color: #a1a1a1;
+      }
+    }
+  }
+
+  .layered {
+    box-shadow: 0 1px 1px hsla(0deg, 0%, 0%, 0.075), 0 5px 10px hsla(0deg, 0%, 0%, 0.075),
+      0 4px 4px hsla(0deg, 0%, 0%, 0.075), 0 -1px 0px hsla(0deg, 0%, 0%, 0.075),
+      0 6px 8px hsla(0deg, 0%, 0%, 0.025);
+  }
+}
+
+::v-deep view.data-v-1481d46d,
+scroll-view.data-v-1481d46d,
+swiper-item.data-v-1481d46d {
+  margin: 0 4rpx;
+}
+
+::v-deep view.data-v-39e33bf2,
+scroll-view.data-v-39e33bf2,
+swiper-item.data-v-39e33bf2 {
+  margin-bottom: 10rpx !important;
+}
+</style>