Prechádzať zdrojové kódy

feat: 增加搜索商品页面

Moss 1 rok pred
rodič
commit
5e9ef2b623

+ 6 - 0
src/pages.json

@@ -109,6 +109,12 @@
       }
     },
     {
+      "path": "pages/goods/search",
+      "style": {
+        "navigationBarTitleText": "商品搜索"
+      }
+    },
+    {
       "path": "pages/goods/list",
       "style": {
         "navigationBarTitleText": "商品列表"

+ 2 - 2
src/pages/goods/list.vue

@@ -31,7 +31,7 @@
         <view class="title">{{item.title}}</view>
         <view class="des">{{item.content}}</view>
         <view class="imgs">
-          <image :src="imgUrl + it.imgUrl" v-for="(it, idx) in item.goodsFiles" :key="idx" mode="aspectFill"></image>
+          <image :src="imageUrl + it.imgUrl" v-for="(it, idx) in item.goodsFiles" :key="idx" mode="aspectFill"></image>
         </view>
         <view class="bottom">
           <view class="left-location"><text class="iconfont icon-dingwei"></text>{{item.city}} {{item.area}}</view>
@@ -66,7 +66,7 @@
   export default {
     data() {
       return {
-        imgUrl: this.$imageUrl,
+        imageUrl: this.$imageUrl,
         categoryList: [],
         categoryId: '',
         tabList: [{

+ 297 - 0
src/pages/goods/search.vue

@@ -0,0 +1,297 @@
+<template>
+  <!-- #ifdef H5 -->
+  <zj-page-layout
+    :hasFooter="false"
+    :isScroll="isShowKeyword ? false : true"
+    :refresherTriggered="refresherTriggered"
+    @refresherrefresh="refresherrefresh"
+    @scrolltolower="scrolltolower">
+    <template slot="header">
+      <view class="search-container">
+        <u-search
+          placeholder="输入商品名称搜索"
+          showAction
+          :actionText="isShowKeyword ? '搜索' : '取消'"
+          clearabled
+          v-model="keyword"
+          @search="searchData"
+          @custom="isShowKeyword ? searchData() : cancelSearch()"
+          @clear="searchData"
+          @focus="isShowKeyword = true"
+          >
+        </u-search>
+      </view>
+    </template>
+
+    <view class="keyword-container" v-if="isShowKeyword">
+      <view class="group">
+        <view class="title">
+          <view class="left">猜你想搜</view>
+        </view>
+        <view class="list">
+          <view class="item" v-for="(item, index) in keyword1List" :key="index" @tap="clickKeyword(item)">{{item}}</view>
+        </view>
+      </view>
+      <view class="group">
+        <view class="title">
+          <view class="left">最近搜索</view>
+          <view class="right">
+            <view class="item del" @tap="deleteKeyword"><text class="iconfont icon-shanchu"></text></view>
+          </view>
+        </view>
+        <view class="list">
+          <view class="item" v-for="(item, index) in keyword2List.slice(0, isOpen ? keyword2List.length : 10)" :key="index" @tap="clickKeyword(item)">{{item}}</view>
+          <view class="item" @tap="isOpen = !isOpen" v-if="keyword2List.length > 10">{{isOpen ? '收起' : '展开'}}<u-icon size="14" :name="isOpen ? 'arrow-up' : 'arrow-down'"></u-icon></view>
+        </view>
+      </view>
+    </view>
+
+    <block v-else>
+      <view class="common-goods-list">
+        <view class="item" v-for="(item, index) in dataList" :key="index" @tap="toGoodsDetail(item.id)">
+          <view class="soldout" v-if="item.status === 4">
+            <image src="@/static/common/soldout.png" mode="widthFix"></image>
+          </view>
+          <view class="top">
+            <image :src="item.userPic ? (imageUrl + item.userPic) : require('@/static/common/logo.png')"></image>
+            <view class="user">
+              <view class="name">{{item.userName}}</view>
+              <view class="time">{{item.createTime}}</view>
+            </view>
+            <view class="price">{{item.amount | priceFilter2}}</view>
+          </view>
+          <view class="title">{{item.title}}</view>
+          <view class="des">{{item.content}}</view>
+          <view class="imgs">
+            <image :src="imageUrl + it.imgUrl" v-for="(it, idx) in item.goodsFiles" :key="idx" mode="aspectFill"></image>
+          </view>
+          <view class="bottom">
+            <view class="left-location"><text class="iconfont icon-dingwei"></text>{{item.city}} {{item.area}}</view>
+            <view class="right-stats">
+              <view class="it">
+                <text class="iconfont icon-liulan"></text>
+                <text class="text">{{item.visit || 0}}</text>
+              </view>
+              <view class="it">
+                <text class="iconfont icon-dianzan"></text>
+                <text class="text">{{item.up || 0}}</text>
+              </view>
+              <view class="it">
+                <text class="iconfont icon-shoucang"></text>
+                <text class="text">{{item.collectNum || 0}}</text>
+              </view>
+            </view>
+          </view>
+        </view>
+      </view>
+      <Loading :loadStatus="loadStatus" :dataList="dataList" />
+    </block>
+
+  </zj-page-layout>
+  <!-- #endif -->
+
+  <!-- #ifndef H5 -->
+  <web-view :src="webViewHref(`/pages/goods/search`, pam, crossPagePam)" @message="crossPage.$listener"></web-view>
+  <!-- #endif -->
+</template>
+
+<script>
+  // #ifdef H5
+  export default {
+    data() {
+      return {
+        imageUrl: this.$imageUrl,
+        refresherTriggered: false,
+        keyword: '',
+        keyword1List: [],
+        keyword2List: [],
+
+        isShowKeyword: true,
+
+        dataList: [],
+        pageNum: 1,
+        loadStatus: 0,
+
+        isOpen: false,
+      }
+    },
+
+    watch: {
+      isShowKeyword() {
+        this.keyword2List = uni.getStorageSync('goodsSearchKeywords') || [];
+      }
+    },
+
+    onLoad() {
+      this.crossPage.$on('reloadGoodsListPage', () => {
+        this.refreshList();
+      })
+      
+      this.getThink();
+      this.keyword2List = uni.getStorageSync('goodsSearchKeywords') || [];
+    },
+    
+    onUnload() {
+      this.crossPage.$off('reloadGoodsListPage');
+    },
+
+    methods: {
+      getThink() {
+        this.$api.get('/goods/getThink')
+        .then(res => {
+          this.keyword1List = res.data || [];
+        })
+      },
+
+      //获取列表数据
+      async getList() {
+        this.$api.get('/goods/list', {
+          pageNum: this.pageNum,
+          pageSize: 10,
+          title: this.keyword,
+        }).then(res => {
+          this.loadStatus = 0;
+          let list = res.data.records;
+          if (list.length < 10) {
+            this.loadStatus = 2;
+          }
+          this.dataList = this.dataList.concat(list);
+        }).catch(() => {
+          this.loadStatus = 2;
+        }).finally(() => {
+          this.refresherTriggered = false;
+        })
+      },
+
+      refreshList() {
+        this.dataList = [];
+        this.pageNum = 1;
+        this.getList();
+      },
+
+      clickKeyword(val) {
+        this.keyword = val;
+        this.searchData();
+      },
+
+      searchData() {
+        if(this.keyword) {
+          let list = uni.getStorageSync('goodsSearchKeywords') || [];
+          let index = list.indexOf(this.keyword);
+          if(index >= 0) {
+            list.splice(index, 1);
+            list.unshift(this.keyword);
+          }else {
+            list.unshift(this.keyword);
+          }
+          uni.setStorageSync('goodsSearchKeywords', list);
+        }
+        this.isShowKeyword = false;
+        this.refreshList();
+      },
+
+      cancelSearch() {
+        this.isShowKeyword = true;
+        this.keyword = '';
+      },
+
+      deleteKeyword() {
+        uni.removeStorageSync('goodsSearchKeywords');
+        this.keyword2List = [];
+      },
+
+      // 滚动到底部
+      scrolltolower(e) {
+        if (this.loadStatus === 0) {
+          this.pageNum++;
+          this.getList();
+        }
+      },
+
+      // 触发下拉刷新
+      async refresherrefresh(e) {
+        this.refresherTriggered = true;
+        this.refreshList();
+      },
+
+      toGoodsDetail(id) {
+        this.$navToPage({
+          url: `/pages/goods/detail?id=${id}`
+        })
+      },
+    },
+  }
+
+  // #endif
+  // #ifndef H5
+  export default {
+    data() {
+      return {
+        pam: {},
+      }
+    },
+    onLoad(pam) {
+      this.pam = pam;
+    }
+  }
+  // #endif
+</script>
+
+<style lang="scss" scoped>
+.search-container {
+  background: #ffffff;
+  padding: 0 30rpx 20rpx;
+}
+
+.keyword-container {
+  height: 100%;
+  background: #ffffff;
+  box-sizing: border-box;
+  padding: 1rpx 30rpx;
+  .group {
+    .title {
+      margin-top: 40rpx;
+      display: flex;
+      justify-content: space-between;
+      .left {
+        font-size: 28rpx;
+        font-weight: 500;
+      }
+      .right {
+        display: flex;
+        align-items: center;
+        .item {
+          display: flex;
+          align-items: center;
+        }
+        .del {
+          text {
+            font-size: 32rpx;
+          }
+          margin-left: 30rpx;
+          color: $reg-font;
+          font-weight: 600;
+        }
+      }
+    }
+    .list {
+      display: flex;
+      flex-wrap: wrap;
+      .item {
+        margin-top: 20rpx;
+        font-size: 22rpx;
+        background: rgb(242, 242, 242);
+        margin-right: 20rpx;
+        height: 44rpx;
+        display: flex;
+        align-items: center;
+        border-radius: 44rpx;
+        padding: 0 24rpx;
+        ::v-deep .u-icon {
+          margin-left: 4rpx;
+        }
+      }
+    }
+  }
+}
+</style>

+ 7 - 4
src/pages/index/index.vue

@@ -10,8 +10,12 @@
       </template> -->
 
       <view class="all-container">
-        <view class="search-container">
-          <u-search placeholder="输入商品名称搜索" :showAction="false" clearabled v-model="keyword" @search="handleSearch">
+        <view class="search-container" @tap.stop="handleSearch">
+          <u-search
+            placeholder="输入商品名称搜索"
+            :showAction="false"
+            clearabled
+            :disabled="true">
           </u-search>
         </view>
 
@@ -244,9 +248,8 @@
 
       handleSearch() {
         this.$navToPage({
-          url: `/pages/goods/list?keyword=${this.keyword}`
+          url: `/pages/goods/search`
         })
-        this.keyword = '';
       },
 
       toGoodsList(categoryId) {

+ 7 - 3
src/styles/iconfont.css

@@ -1,9 +1,9 @@
 /* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
 @font-face {
   font-family: 'iconfont';  /* Project id 4308323 */
-  src: url('https://at.alicdn.com/t/c/font_4308323_aieqfc49e5s.woff2?t=1699351867855') format('woff2'),
-       url('https://at.alicdn.com/t/c/font_4308323_aieqfc49e5s.woff?t=1699351867855') format('woff'),
-       url('https://at.alicdn.com/t/c/font_4308323_aieqfc49e5s.ttf?t=1699351867855') format('truetype');
+  src: url('https://at.alicdn.com/t/c/font_4308323_f06iy5i753c.woff2?t=1701226729193') format('woff2'),
+       url('https://at.alicdn.com/t/c/font_4308323_f06iy5i753c.woff?t=1701226729193') format('woff'),
+       url('https://at.alicdn.com/t/c/font_4308323_f06iy5i753c.ttf?t=1701226729193') format('truetype');
 }
 
 .iconfont {
@@ -14,6 +14,10 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-shanchu:before {
+  content: "\e645";
+}
+
 .icon-duihua:before {
   content: "\e619";
 }