Explorar o código

feat(xsb): 添加商品搜索功能及相关接口支持

新增商品搜索页面及接口调用逻辑,包括:
- 新增搜索页面 `search/index.vue` 实现关键词搜索、历史记录管理与热门搜索展示
- 添加全局状态存储搜索历史
- 注册搜索相关 API 接口类型定义和方法配置
- 页面路由注册及跳转支持
- 优化搜索输入框样式与交互体验
zhangtao hai 6 días
pai
achega
3c518a3bed

+ 1 - 0
src/api/api.type.d.ts

@@ -170,4 +170,5 @@ namespace Api {
     pointsTotal?: number
     [property: string]: any
   }
+
 }

+ 1 - 0
src/api/apiDefinitions.ts

@@ -30,4 +30,5 @@ export default {
   'xsb.getProductDetail':['GET', '/smqjh-pms/app-api/v1/spu/getProductDetails'],
   'xsb.findUserPointsPage':['PUT', '/smqjh-system/app-api/v1/points/findUserPointsPage'],
   'xsb.findUserPoints':['GET', '/smqjh-system/app-api/v1/points/findUserPoints'],
+  'xsb.getSearchProductList':['POST', '/smqjh-pms/app-api/v1/spu/getSearchProductList'],
 };

+ 34 - 6
src/api/globals.d.ts

@@ -118,7 +118,7 @@ declare global {
     }
     xsb: {
       categories<
-        Config extends Alova2MethodConfig<Api.xsbCategories []> & {
+        Config extends Alova2MethodConfig<Api.xsbCategories[]> & {
           data: {
             channelId: number;
             shopId: number
@@ -126,9 +126,9 @@ declare global {
         }
       >(
         config: Config
-      ): Alova2Method<Api.xsbCategories [], 'xsb.categories', Config>;
+      ): Alova2Method<Api.xsbCategories[], 'xsb.categories', Config>;
       getCategoryProductList<
-        Config extends Alova2MethodConfig<Api.xsbCategoryProductList []> & {
+        Config extends Alova2MethodConfig<Api.xsbCategoryProductList[]> & {
           data: {
             categoryId: number;
             shopId: number
@@ -136,16 +136,16 @@ declare global {
         }
       >(
         config: Config
-      ): Alova2Method<Api.xsbCategoryProductList [], 'xsb.getCategoryProductList', Config>;
+      ): Alova2Method<Api.xsbCategoryProductList[], 'xsb.getCategoryProductList', Config>;
       getProductDetail<
-        Config extends Alova2MethodConfig< Api.xsbProductDetail> & {
+        Config extends Alova2MethodConfig<Api.xsbProductDetail> & {
           data: {
             id: number;
           };
         }
       >(
         config: Config
-      ): Alova2Method< Api.xsbProductDetail, 'xsb.getProductDetail', Config>;
+      ): Alova2Method<Api.xsbProductDetail, 'xsb.getProductDetail', Config>;
       findUserPoints<
         Config extends Alova2MethodConfig<Api.xsbFindUserPoints> & {
 
@@ -163,6 +163,34 @@ declare global {
       >(
         config: Config
       ): Alova2Method<listData<Api.xsbFindUserPointsPage>, 'xsb.findUserPointsPage', Config>;
+      getSearchProductList<
+        Config extends Alova2MethodConfig<listData<Api.xsbCategoryProductList>> & {
+          data: {
+            /**
+   * 暂定为商品名称,后面可能会加其他条件
+   */
+            keywords?: string;
+            /**
+             * 页码
+             */
+            pageNum?: number;
+            /**
+             * 每页记录数
+             */
+            pageSize?: number;
+            /**
+             * 价格排序不传时为空,默认不排 ASC:价格升序,DESC:价格倒序
+             */
+            priceSort?: string;
+            /**
+             * 销量排序不传时为空,默认不排 ASC:价格升序,DESC:价格倒序
+             */
+            salesNum?: string;
+          };
+        }
+      >(
+        config: Config
+      ): Alova2Method<listData<Api.xsbCategoryProductList>, 'xsb.getSearchProductList', Config>;
     }
 
   }

+ 9 - 0
src/pages.json

@@ -131,6 +131,15 @@
             "navigationBarTitleText": "星闪豹订单列表",
             "disableScroll": true
           }
+        },
+        {
+          "path": "search/index",
+          "type": "page",
+          "name": "xsb-search",
+          "islogin": false,
+          "style": {
+            "navigationBarTitleText": "搜索"
+          }
         }
       ]
     },

+ 1 - 1
src/subPack-xsb/commonTab/components/index.vue

@@ -83,7 +83,7 @@ function handleSwiperClick(e: { index: number, item: Api.xsbCategories }) {
         class="header-linear h320rpx px24rpx"
         :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }"
       >
-        <view class="h60rpx w-full flex items-center justify-between rounded-40rpx bg-white pr6rpx">
+        <view class="h60rpx w-full flex items-center justify-between rounded-40rpx bg-white pr6rpx" @click="router.push({ name: 'xsb-search' })">
           <view class="flex items-center pb14rpx pl24rpx pt16rpx">
             <wd-icon name="search" size="14" color="#ccc" />
             <view class="search ml12rpx h-full w-full overflow-hidden">

+ 145 - 0
src/subPack-xsb/search/index.vue

@@ -0,0 +1,145 @@
+<script setup lang="ts">
+definePage({
+  name: 'xsb-search',
+  islogin: false,
+  style: {
+    navigationBarTitleText: '搜索',
+  },
+})
+const { searchList } = storeToRefs(useSysXsbStore())
+const searchText = ref()
+const tabbarlist = ref([
+  { name: '综合', id: 0 },
+  { name: '销量', id: 1 },
+  { name: '价格', id: 2 },
+])
+const activeTab = ref(0)
+const { confirm: showConfirm } = useGlobalMessage()
+
+const { data, send, isLastPage, page } = usePagination((pageNum, pageSize) => Apis.xsb.getSearchProductList({ data: {
+  keywords: searchText.value,
+  pageNum,
+  pageSize,
+  priceSort: activeTab.value === 2 ? 'DESC' : '',
+  salesNum: activeTab.value === 1 ? 'DESC' : '',
+} }), {
+  immediate: false,
+  data: resp => resp.list,
+  initialPage: 1,
+  initialPageSize: 10,
+  append: true,
+})
+const isSearch = ref(false)
+function handleSearch() {
+  data.value = []
+  isSearch.value = true
+  send()
+  searchList.value.push(searchText.value)
+}
+watch(() => searchText.value, () => {
+  if (!searchText.value) {
+    isSearch.value = false
+  }
+})
+onReachBottom(() => {
+  if (!isLastPage.value) {
+    page.value++
+  }
+})
+function handleChange(e: { index: number }) {
+  activeTab.value = e.index
+  data.value = []
+  send()
+}
+function handleClearnSeachLocaData() {
+  showConfirm({
+    title: '警告',
+    msg: '是否删除历史搜索记录?',
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    success() {
+      searchList.value = []
+    },
+  })
+}
+</script>
+
+<template>
+  <view class="page-xsb">
+    <view class="sticky top-0 bg-white px24rpx pt24rpx">
+      <view class="box-border flex items-center justify-between border border-2rpx border-[var(--them-color)] rounded-40rpx border-solid px24rpx py14rpx">
+        <view class="flex items-center">
+          <wd-icon name="search" size="20px" color="#aaa" />
+          <input v-model="searchText" type="text" placeholder="请输入搜索内容" class="ml20rpx">
+        </view>
+        <view class="flex items-center">
+          <view class="ml12rpx text-#DEDEDE">
+            |
+          </view>
+          <view class="ml12rpx text-28rpx text-[var(--them-color)] font-semibold" @click="handleSearch">
+            搜索
+          </view>
+        </view>
+      </view>
+      <view v-if="!isSearch" class="h-90vh">
+        <view v-if="searchList.length" class="mt24rpx">
+          <view class="flex items-center justify-between">
+            <view class="text-28rpx font-semibold">
+              历史搜索
+            </view>
+            <wd-icon name="delete-thin" size="22px" @click="handleClearnSeachLocaData" />
+          </view>
+          <view class="mt20rpx flex flex-wrap items-center">
+            <view v-for="item in searchList" :key="item" class="mr16rpx flex items-center justify-center rounded-30rpx bg-#F6F6F6 px24rpx py10rpx">
+              {{ item }}
+            </view>
+          </view>
+        </view>
+        <view class="mt24rpx">
+          <view class="text-28rpx font-semibold">
+            热门搜索
+          </view>
+        </view>
+      </view>
+      <view v-if="isSearch">
+        <wd-tabs v-model="activeTab" @change="handleChange">
+          <block v-for="item in tabbarlist" :key="item.id">
+            <wd-tab :title="item.name" />
+          </block>
+        </wd-tabs>
+      </view>
+    </view>
+    <view v-if="isSearch" class="px24rpx pt20rpx">
+      <view v-for="item in data" :key="item.id" class="mb20rpx box-border flex items-center justify-between rounded-16rpx bg-white p24rpx">
+        <image
+          :src="item.pic"
+          class="h200rpx w200rpx flex-shrink-0 rounded-16rpx"
+        />
+        <view class="ml20rpx flex-1">
+          <view class="text-32rpx font-semibold">
+            {{ item.prodName }}
+          </view>
+          <view class="mt14rpx text-36rpx text-#FF4A39 font-semibold">
+            ¥{{ item.channelProdPrice }}
+          </view>
+        </view>
+      </view>
+      <wd-status-tip v-if="!data.length" image="search" tip="当前搜索无结果" />
+    </view>
+    <view class="h30rpx" />
+  </view>
+</template>
+
+<style scoped lang="scss">
+.page-xsb{
+  :deep(){
+    .wd-tabs__nav-item-text{
+      font-size: 28rpx !important;
+    }
+    .wd-tabs__nav-item.is-active{
+      font-weight: 700 !important;
+      color: var(--them-color) !important;
+    }
+  }
+}
+</style>

+ 2 - 0
src/subPack-xsb/store-xsb/sys.ts

@@ -10,12 +10,14 @@ interface SysState {
    * 二级分类激活id
    */
   leftActive: string
+  searchList: string[]
 }
 export const useSysXsbStore = defineStore('system-xsb', {
   state: (): SysState => ({
     ScrollDown: false,
     topNavActive: '',
     leftActive: '',
+    searchList: [],
   }),
   actions: {
     getTabbarItemValue(name: string) {

+ 1 - 0
src/uni-pages.d.ts

@@ -12,6 +12,7 @@ type _LocationUrl =
   "/subPack-xsb/commonTab/index" |
   "/subPack-xsb/goods/index" |
   "/subPack-xsb/order/index" |
+  "/subPack-xsb/search/index" |
   "/subPack-common/address/index" |
   "/subPack-common/afterSales/index" |
   "/subPack-common/afterSalesDetail/index" |