Преглед изворни кода

feat(app): 实现全局搜索功能

- 新增 SearchDTO 作为全局搜索的入参对象
- 在 AppHomeService 中实现 search 方法,支持不同类型的搜索
- 在 AppSiteMapper 和 AppCoureseMapper 中添加相应的查询方法
-优化 PlaceVO 和 SearchVO 中的字段,以支持搜索结果的展示
SheepHy пре 3 недеља
родитељ
комит
e80b6f3fd0

+ 2 - 2
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/AppHomeController.java

@@ -29,7 +29,7 @@ public class AppHomeController {
     private IUserService userService;
 
     @GetMapping("/homeInfo")
-    @Operation(summary = "查询首页轮播图")
+    @Operation(summary = "首页基础数据查询")
     public Result<HomeVO> homeInfo() {
         return Result.ok(appHomeService.homeInfo());
     }
@@ -66,7 +66,7 @@ public class AppHomeController {
      * @return
      **/
     @PostMapping("/getPlaceList")
-    @Operation(summary = "场地列表查询")
+    @Operation(summary = "场地列表查询 词典CODE:venue_type")
     public Result<Page<PlaceVO>> getPlaceList(@RequestBody GetPlaceListDTO getPlaceListDTO){
         return Result.ok(appHomeService.getPlaceList(getPlaceListDTO));
     }

+ 15 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/SearchDTO.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.app.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="全局搜索入参DTO")
+public class SearchDTO  extends GetPlaceListDTO{
+    @Schema(description ="关键字")
+    private String keyword;
+}

+ 11 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IAppHomeService.java

@@ -2,6 +2,7 @@ package org.jeecg.modules.app.service;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.jeecg.modules.app.dto.GetPlaceListDTO;
+import org.jeecg.modules.app.dto.SearchDTO;
 import org.jeecg.modules.app.vo.AppBannerVO;
 import org.jeecg.modules.app.vo.HomeVO;
 import org.jeecg.modules.app.vo.PlaceVO;
@@ -24,4 +25,14 @@ public interface IAppHomeService {
      * @return
      **/
     Page<PlaceVO> getPlaceList(GetPlaceListDTO getPlaceListDTO);
+
+    /**
+     * @Author SheepHy
+     * @Description 全局搜索
+     * @Date 10:37 2025/7/4
+     * @Param
+     * @return
+     **/
+    Object search(SearchDTO searchDTO);
+
 }

+ 80 - 9
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/AppHomeServiceImpl.java

@@ -3,6 +3,7 @@ package org.jeecg.modules.app.service.impl;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.jeecg.modules.app.dto.GetPlaceListDTO;
+import org.jeecg.modules.app.dto.SearchDTO;
 import org.jeecg.modules.app.service.IAppHomeService;
 import org.jeecg.modules.app.vo.*;
 import org.jeecg.modules.system.app.entity.AppBanner;
@@ -142,18 +143,13 @@ public class AppHomeServiceImpl implements IAppHomeService {
         Page<PlaceVO> page = new Page<>(getPlaceListDTO.getCurrent(), getPlaceListDTO.getSize());
         Page<PlaceVO> placeList = appSiteMapper.getPlaceList(page, getPlaceListDTO.getVenueType());
         placeList.getRecords().forEach(placeVO -> {
-            List<String> list = new ArrayList<>();
-            String[] split = placeVO.getCategoryId().split(",");
-            Arrays.stream(split).forEach(id -> {
-                list.add(appCategoryMapper.selectById(id).getName());
-            });
             //todo 待申请第三方地图接口
             placeVO.setKm(0.0)
-                    .setCategory(list);
+                    .setCategory(getCategoryName(placeVO.getCategoryId()));
         });
-        if(getPlaceListDTO.getVenueType().equals("1")
-                || getPlaceListDTO.getVenueType().equals("2")
-                || getPlaceListDTO.getVenueType().equals("3")){
+        if(getPlaceListDTO.getVenueType().equals("0-2")
+                || getPlaceListDTO.getVenueType().equals("1-1")
+                || getPlaceListDTO.getVenueType().equals("2-1")){
             // 按 km 升序排序(从近到远)
             placeList.getRecords().sort((p1, p2) -> {
                 Double km1 = p1.getKm();
@@ -163,4 +159,79 @@ public class AppHomeServiceImpl implements IAppHomeService {
         }
         return placeList;
     }
+
+    @Override
+    public Object search(SearchDTO searchDTO) {
+        switch (searchDTO.getVenueType().charAt(0)) {
+            case '0':
+                    return convertSearchPlaceVOPage(searchDTO);
+            case '1':
+                    return convertSearchTrainVOPage(searchDTO);
+            case '2':
+                    return new Page<>();
+            case '3':
+                    return new Page<>();
+        }
+        return new Page<>();
+    }
+    /**
+     * @Author SheepHy
+     * @Description 全局搜索场地分页查询
+     * @Date 11:05 2025/7/7
+     * @Param searchDTO {@link SearchDTO}
+     * @return Page<SearchVO.SearchPlaceVO>
+     **/
+    private Page<SearchVO.SearchPlaceVO> convertSearchPlaceVOPage(SearchDTO searchDTO) {
+        Page<SearchVO.SearchPlaceVO> page = new Page<>(searchDTO.getCurrent(), searchDTO.getSize());
+        Page<SearchVO.SearchPlaceVO> searchPlaceVOPage = appSiteMapper.convertSearchPlaceVOPage(page, searchDTO);
+        searchPlaceVOPage.getRecords().forEach(placeVO -> {
+            //todo 待申请第三方地图接口
+            placeVO.setKm(0.0)
+                    .setCategory(getCategoryName(placeVO.getCategoryId()));
+        });
+        if(searchDTO.getVenueType().equals("0-2")
+                || searchDTO.getVenueType().equals("1-1")
+                || searchDTO.getVenueType().equals("2-1")){
+            // 按 km 升序排序(searchDTO)
+            searchPlaceVOPage.getRecords().sort((p1, p2) -> {
+                Double km1 = p1.getKm();
+                Double km2 = p2.getKm();
+                return km1.compareTo(km2);
+            });
+        }
+        return searchPlaceVOPage;
+    }
+    /**
+     * @Author SheepHy
+     * @Description 根据类目ID获取完整的类目名称
+     * @Date 13:31 2025/7/7
+     * @Param categoryId 类目ID
+     * @return List<String>
+     **/
+    private List<String> getCategoryName(String categoryId) {
+        List<String> list = new ArrayList<>();
+        String[] split = categoryId.split(",");
+        Arrays.stream(split).forEach(id -> {
+            list.add(appCategoryMapper.selectById(id).getName());
+        });
+        return list;
+    }
+
+    /**
+     * @Author SheepHy
+     * @Description 培训课程分页查询
+     * @Date 13:37 2025/7/7
+     * @Param
+     * @return
+     **/
+    private Page<SearchVO.SearchTrainVO> convertSearchTrainVOPage(SearchDTO searchDTO) {
+        Page<SearchVO.SearchTrainVO> page = new Page<>(searchDTO.getCurrent(), searchDTO.getSize());
+        Page<SearchVO.SearchTrainVO> searchTrainVOPage = appCoureseMapper.convertSearchTrainVOPage(page, searchDTO);
+        searchTrainVOPage.getRecords().forEach(trainVO -> {
+            //todo 待申请第三方地图接口
+            trainVO.setKm(0.0);
+        });
+        return searchTrainVOPage;
+    }
+
 }

+ 9 - 2
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/SearchVO.java

@@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
 import java.math.BigDecimal;
+import java.util.Date;
 import java.util.List;
 
 @Data
@@ -105,6 +106,8 @@ public class SearchVO{
         private BigDecimal originalPrice;
         @Schema(description = "课程售价")
         private BigDecimal sellingPrice;
+        @Schema(description = "销售数量")
+        private int sales;
         @Schema(description = "好评率")
         private BigDecimal goodRate;
         @Schema(description = "评论数")
@@ -115,6 +118,10 @@ public class SearchVO{
         private String address;
         @Schema(description = "距离(KM)")
         private double km;
+        @Schema(description = "课程开始时间")
+        private Date startTime;
+        @Schema(description = "课程结束时间")
+        private Date endTime;
     }
 
     @Data
@@ -138,8 +145,8 @@ public class SearchVO{
         private List<String> category;
         @Schema(hidden = true)
         private String categoryId;
-        @Schema(description = "全局搜索产品信息返回参数")
-        private List<SearchCoureseVO> searchCoureseList;
+        @Schema(description = "是否有票")
+        private boolean ticketWhether;
     }
     @Data
     @Accessors(chain = true)

+ 12 - 4
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppCoureseMapper.java

@@ -1,10 +1,11 @@
 package org.jeecg.modules.system.app.mapper;
 
-import java.util.List;
-
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.app.dto.SearchDTO;
+import org.jeecg.modules.app.vo.SearchVO;
 import org.jeecg.modules.system.app.entity.AppCourese;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 
 /**
  * @Description: 课程/培训表
@@ -13,5 +14,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  * @Version: V1.0
  */
 public interface AppCoureseMapper extends BaseMapper<AppCourese> {
-
+    /**
+     * @Author SheepHy
+     * @Description 培训课程分页查询
+     * @Date 13:37 2025/7/7
+     * @Param
+     * @return
+     **/
+    Page<SearchVO.SearchTrainVO> convertSearchTrainVOPage(@Param("page")Page<SearchVO.SearchTrainVO> page,@Param("searchDTO")SearchDTO searchDTO);
 }

+ 11 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppSiteMapper.java

@@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.app.dto.SearchDTO;
 import org.jeecg.modules.app.vo.PlaceVO;
+import org.jeecg.modules.app.vo.SearchVO;
 import org.jeecg.modules.system.app.entity.AppSite;
 
 /**
@@ -24,4 +26,13 @@ public interface AppSiteMapper extends BaseMapper<AppSite> {
      **/
     Page<PlaceVO> getPlaceList(@Param("page")IPage<PlaceVO> page, @Param("venueType")String venueType);
 
+    /**
+     * @Author SheepHy
+     * @Description 全局搜索场地分页查询
+     * @Date 11:05 2025/7/7
+     * @Param searchDTO {@link SearchDTO}
+     * @return Page<SearchVO.SearchPlaceVO>
+     **/
+    Page<SearchVO.SearchPlaceVO> convertSearchPlaceVOPage(@Param("page")Page<SearchVO.SearchPlaceVO> page,@Param("searchDTO")SearchDTO searchDTO);
+
 }

+ 33 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppCoureseMapper.xml

@@ -1,5 +1,37 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.jeecg.modules.system.app.mapper.AppCoureseMapper">
-
+    <select id="convertSearchTrainVOPage" resultType="org.jeecg.modules.app.vo.SearchVO$SearchTrainVO">
+        SELECT
+            a.id,
+            a.`name`,
+            b.address,
+            a.original_price,
+            a.selling_price,
+            COALESCE(d.sales, 0) AS sales,
+            a.good_rate,
+            a.start_time,
+            a.end_time
+        FROM
+            nm_courses a
+                LEFT JOIN nm_site b ON a.tenant_id = b.tenant_id
+                LEFT JOIN (
+                SELECT
+                    product_id,
+                    COUNT(id) AS sales
+                FROM
+                    nm_order_product
+                GROUP BY
+                    product_id
+            ) d ON a.id = d.product_id WHERE 1 = 1
+        <if test="searchDTO.keyword != null and searchDTO.keyword == ''">
+            AND (a.name LIKE CONCAT('%',#{searchDTO.keyword},'%') OR a.address LIKE CONCAT('%',#{searchDTO.keyword},'%'))
+        </if>
+        <if test="searchDTO.venueType != null and searchDTO.venueType == '1-2'">
+            ORDER BY  a.good_rate DESC
+        </if>
+        <if test="searchDTO.venueType != null and searchDTO.venueType == '1-3'">
+            ORDER BY sales DESC
+        </if>
+    </select>
 </mapper>

+ 29 - 5
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSiteMapper.xml

@@ -17,20 +17,44 @@
                 ELSE 0
                 END AS ticketWhether
         FROM nm_site a LEFT JOIN sys_depart b ON a.tenant_id = b.id WHERE 1=1
-        <if test="venueType != null and venueType == 0">
+        <if test="venueType != null and venueType == '0-1'">
             ORDER BY  a.good_rate DESC
         </if>
-        <if test="venueType != null and venueType == 1">
+        <if test="venueType != null and venueType == '1-1'">
             AND b.org_category = 2
         </if>
-        <if test="venueType != null and venueType == 2">
+        <if test="venueType != null and venueType == '1-2'">
             AND b.org_category = 2 ORDER BY  a.good_rate DESC
         </if>
-        <if test="venueType != null and venueType == 3">
+        <if test="venueType != null and venueType == '2-1'">
             AND b.org_category = 3
         </if>
-        <if test="venueType != null and venueType == 4">
+        <if test="venueType != null and venueType == '2-2'">
             AND b.org_category = 3 ORDER BY  a.good_rate DESC
         </if>
     </select>
+
+    <select id="convertSearchPlaceVOPage" resultType="org.jeecg.modules.app.vo.SearchVO$SearchPlaceVO" parameterType="org.jeecg.modules.app.dto.SearchDTO">
+        SELECT
+        a.id,
+        a.name,
+        a.good_rate AS goodRate,
+        a.address,
+        a.category_id,
+        CASE
+        WHEN EXISTS (
+        SELECT SUM(inventory)
+        FROM nm_site_peice_rules
+        WHERE site_id = a.id
+        ) THEN 1
+        ELSE 0
+        END AS ticketWhether
+        FROM nm_site a LEFT JOIN sys_depart b ON a.tenant_id = b.id WHERE 1=1
+        <if test="searchDTO.keyword != null and searchDTO.keyword == ''">
+            AND (a.name LIKE CONCAT('%',#{searchDTO.keyword},'%') OR a.address LIKE CONCAT('%',#{searchDTO.keyword},'%'))
+        </if>
+        <if test="searchDTO.venueType != null and searchDTO.venueType == '0-2'">
+            ORDER BY  a.good_rate DESC
+        </if>
+    </select>
 </mapper>