Quellcode durchsuchen

首页陪玩类目展示、热门陪玩商户、热门项目

郭子栋 vor 9 Stunden
Ursprung
Commit
f042176a95
16 geänderte Dateien mit 690 neuen und 3 gelöschten Zeilen
  1. 53 0
      nightFragrance-massage/src/main/java/com/ylx/companion/controller/CompanionRecommendController.java
  2. 57 0
      nightFragrance-massage/src/main/java/com/ylx/companion/domain/dto/CompanionAllMerchantsDTO.java
  3. 47 0
      nightFragrance-massage/src/main/java/com/ylx/companion/domain/dto/CompanionRecommendDTO.java
  4. 55 0
      nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/CompanionAllMerchantsVo.java
  5. 36 0
      nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/CompanionRecommendVO.java
  6. 57 0
      nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/HotCompanionMerchantVO.java
  7. 38 0
      nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/HotCompanionProjectVO.java
  8. 28 0
      nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/ServiceCategoryVO.java
  9. 32 0
      nightFragrance-massage/src/main/java/com/ylx/companion/mapper/CompanionRecommendMapper.java
  10. 17 0
      nightFragrance-massage/src/main/java/com/ylx/companion/service/ICompanionRecommendService.java
  11. 89 0
      nightFragrance-massage/src/main/java/com/ylx/companion/service/impl/CompanionRecommendServiceImpl.java
  12. 15 1
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaProjectMapper.java
  13. 10 0
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaTechnicianMapper.java
  14. 0 1
      nightFragrance-massage/src/main/java/com/ylx/massage/service/IMaProjectService.java
  15. 106 1
      nightFragrance-massage/src/main/resources/mapper/massage/MaProjectMapper.xml
  16. 50 0
      nightFragrance-massage/src/main/resources/mapper/massage/MaTechnicianMapper.xml

+ 53 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/controller/CompanionRecommendController.java

@@ -0,0 +1,53 @@
+package com.ylx.companion.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.common.core.domain.R;
+import com.ylx.companion.domain.dto.CompanionAllMerchantsDTO;
+import com.ylx.companion.domain.dto.CompanionRecommendDTO;
+import com.ylx.companion.domain.vo.CompanionAllMerchantsVo;
+import com.ylx.companion.domain.vo.CompanionRecommendVO;
+import com.ylx.companion.service.ICompanionRecommendService;
+import com.ylx.massage.domain.dto.MassageAllMerchantsDto;
+import com.ylx.massage.domain.vo.MassageAllMerchantsVo;
+import com.ylx.massage.service.IMaProjectService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 类描述:陪玩推荐
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/10 14:12
+ */
+@Api(tags = "陪玩推荐")
+@RestController
+@RequestMapping("/companion/recommend")
+public class CompanionRecommendController {
+    @Autowired
+    private ICompanionRecommendService companionRecommendService;
+
+    @Autowired
+    private IMaProjectService iMaProjectService;
+
+    @ApiOperation("首页陪玩推荐")
+    @PostMapping("/list")
+    public R<?> getRecommend(@RequestBody @Validated CompanionRecommendDTO dto) {
+        CompanionRecommendVO vo = companionRecommendService.getRecommend(dto);
+        return R.ok(vo);
+    }
+
+    @ApiOperation("首页获取陪玩全部商户")
+    @PostMapping("/getCompanionAllMerchants")
+    public R<Page<CompanionAllMerchantsVo>> getCompanionAllMerchants(@RequestBody @Validated CompanionAllMerchantsDTO dto) {
+        Page<CompanionAllMerchantsVo> page = new Page<>(dto.getPageNo(),dto.getPageSize());
+        return R.ok(companionRecommendService.getCompanionAllMerchants(page,dto));
+    }
+
+}

+ 57 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/domain/dto/CompanionAllMerchantsDTO.java

@@ -0,0 +1,57 @@
+package com.ylx.companion.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/**
+ * 类描述:首页陪玩商户推荐点击全部返回所有陪玩商户Dto
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/4 9:31
+ */
+@Data
+public class CompanionAllMerchantsDTO {
+
+    @NotNull(message = "页码不能为空")
+    @ApiModelProperty("页码")
+    private Integer pageNo;
+
+    @NotNull(message = "每页大小不能为空")
+    @ApiModelProperty("每页大小")
+    private Integer pageSize;
+    /**
+     * 经度
+     * 用户当前位置的经度坐标
+     */
+    @NotNull(message = "用户经度不能为空")
+    @ApiModelProperty("用户经度")
+    private BigDecimal longitude;
+
+    /**
+     * 纬度
+     * 用户当前位置的纬度坐标
+     */
+    @NotNull(message = "用户纬度不能为空")
+    @ApiModelProperty("用户纬度")
+    private BigDecimal latitude;
+
+    /**
+     * 城市编码
+     */
+    @NotBlank(message = "城市编码不能为空")
+    @ApiModelProperty("城市编码")
+    private String cityCode;
+
+    /**
+     * 项目id
+     */
+    @ApiModelProperty("项目id")
+    private String projectId;
+
+
+}

+ 47 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/domain/dto/CompanionRecommendDTO.java

@@ -0,0 +1,47 @@
+package com.ylx.companion.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.math.BigDecimal;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/10 10:41
+ */
+@Data
+public class CompanionRecommendDTO {
+    /** 热门项目分页起始页 */
+    private Integer pageNo;
+
+    /** 每页显示记录数 */
+    private Integer pageSize;
+    @NotBlank(message = "类目主键不能为空")
+    @ApiModelProperty("类目主键")
+    private Integer categoryId;
+
+    /**
+     * 经度
+     * 用户当前位置的经度坐标
+     */
+    @ApiModelProperty("用户经度")
+    private BigDecimal longitude;
+
+    /**
+     * 纬度
+     * 用户当前位置的纬度坐标
+     */
+    @ApiModelProperty("用户纬度")
+    private BigDecimal latitude;
+
+    /**
+     * 城市编码
+     */
+    @NotBlank(message = "城市编码不能为空")
+    @ApiModelProperty("城市编码")
+    private String cityCode;
+}

+ 55 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/CompanionAllMerchantsVo.java

@@ -0,0 +1,55 @@
+package com.ylx.companion.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 类描述:首页陪玩商户推荐点击全部返回所有陪玩商户vo
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/4 9:14
+ */
+@Data
+public class CompanionAllMerchantsVo {
+    /**
+     * 项目ID
+     */
+    @ApiModelProperty("项目ID")
+    private String projectId;
+    /**
+     * 项目名称
+     */
+    @ApiModelProperty("项目名称")
+    private String projectName;
+    /**
+     * 商户名称
+     */
+    @ApiModelProperty("商户名称")
+    private String merchantName;
+
+    /**
+     * 商户id
+     */
+    @ApiModelProperty("商户id")
+    private Long merchantId;
+
+    /**
+     * 已服务数量
+     */
+    @ApiModelProperty("已服务订单数量")
+    private Integer nNum;
+    /**
+     * 技师距离(公里)
+     */
+    @ApiModelProperty("技师距离(公里)")
+    private BigDecimal distanceShow;
+    /**
+     * 头像
+     */
+    @ApiModelProperty("商户头像")
+    private String teAvatar;
+
+}

+ 36 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/CompanionRecommendVO.java

@@ -0,0 +1,36 @@
+package com.ylx.companion.domain.vo;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 类描述:首页陪玩推荐VO
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/10 10:06
+ */
+@Data
+public class CompanionRecommendVO {
+
+    /**
+     * 陪玩项目,如台球、棋牌、篮球等
+     */
+    @ApiModelProperty("陪玩项目,如台球、棋牌、篮球等")
+    private List<ServiceCategoryVO> serviceCategoryVoList;
+
+    /**
+     * 热门陪玩商家,查询销量前五
+     */
+    @ApiModelProperty("热门陪玩商家,查询销量前五")
+    private List<HotCompanionMerchantVO> hotCompanionMerchantVoList;
+
+    /**
+     * 热门陪玩商家,销量前五
+     */
+    @ApiModelProperty("热门陪玩项目,查询销量前五")
+    private Page<HotCompanionProjectVO> hotCompanionProjectVoPage;
+}

+ 57 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/HotCompanionMerchantVO.java

@@ -0,0 +1,57 @@
+package com.ylx.companion.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 类描述:热门陪玩商户vo
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/2 15:41
+ */
+@Data
+public class HotCompanionMerchantVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ApiModelProperty("商户id")
+    private Long merchantId;
+
+    /**
+     * 姓名
+     */
+    @ApiModelProperty("商户名")
+    private String merchantName;
+    /**
+     * 评分
+     */
+    @ApiModelProperty("评分")
+    private Integer nStar;
+    /**
+     * 已服务数量
+     */
+    @ApiModelProperty("已服务订单数量")
+    private Integer nNum;
+
+    @ApiModelProperty("技师距离(公里)")
+    private BigDecimal distanceShow;
+
+    /**
+     * 商户开通技能时设置的最低价格
+     */
+    @ApiModelProperty("最低价格")
+    private BigDecimal price;
+
+    /**
+     * 商户形象照
+     */
+    @ApiModelProperty("形象照,展示")
+    private String avatar;
+
+}

+ 38 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/HotCompanionProjectVO.java

@@ -0,0 +1,38 @@
+package com.ylx.companion.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 类描述:热门陪玩项目推荐
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/3 15:43
+ */
+@Data
+public class HotCompanionProjectVO {
+    @ApiModelProperty("项目id")
+    private Long projectId;
+
+
+    /** 项目名称 */
+    @ApiModelProperty("项目名称")
+    private String projectName;
+
+    /** 项目时长(分) */
+    @ApiModelProperty("项目时长(分)")
+    private Long projectDuration;
+
+    @ApiModelProperty("销量")
+    private Integer sales;
+
+    @ApiModelProperty("均价")
+    private BigDecimal avgCurrentPrice;
+
+    @ApiModelProperty("亮点")
+    private String highlight;
+
+}

+ 28 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/domain/vo/ServiceCategoryVO.java

@@ -0,0 +1,28 @@
+package com.ylx.companion.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/10 17:04
+ */
+@Data
+@ApiModel("类目基本信息vo")
+public class ServiceCategoryVO implements Serializable {
+
+    private static final long serialVersionUID = -5680743000457655672L;
+
+    @ApiModelProperty("类目主键")
+    private Integer categoryId;
+
+    @ApiModelProperty("标题")
+    private String title;
+
+}

+ 32 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/mapper/CompanionRecommendMapper.java

@@ -0,0 +1,32 @@
+package com.ylx.companion.mapper;
+
+import com.ylx.companion.domain.vo.HotCompanionProjectVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/10 11:07
+ */
+@Mapper
+public interface CompanionRecommendMapper {
+
+    /**
+     * 查询销量前5的陪玩项目(假设有订单表 t_order 且包含 project_id, status=5 已完成)
+     * 若没有订单表,可暂时返回空或使用降级逻辑
+     */
+    @Select("SELECT p.id as project_id, p.title as project_name, p.standard_duration as project_duration, " +
+            "COUNT(o.id) as sales, AVG(o.final_amount) as avg_current_price, p.highlight " +
+            "FROM project p " +
+            "LEFT JOIN t_order o ON o.project_id = p.id AND o.status = 5 AND o.is_delete = 0 " +
+            "WHERE p.type = 2 AND p.status = 0 AND p.is_delete = 0 " +
+            "GROUP BY p.id " +
+            "ORDER BY sales DESC " +
+            "LIMIT 5")
+    List<HotCompanionProjectVO> selectHotProjects();
+}

+ 17 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/service/ICompanionRecommendService.java

@@ -0,0 +1,17 @@
+package com.ylx.companion.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.companion.domain.dto.CompanionAllMerchantsDTO;
+import com.ylx.companion.domain.dto.CompanionRecommendDTO;
+import com.ylx.companion.domain.vo.CompanionAllMerchantsVo;
+import com.ylx.companion.domain.vo.CompanionRecommendVO;
+import org.apache.ibatis.annotations.Param;
+
+public interface ICompanionRecommendService {
+    /**
+     * 根据项目ID获取陪玩推荐数据
+     */
+    CompanionRecommendVO getRecommend(CompanionRecommendDTO dto);
+
+    Page<CompanionAllMerchantsVo> getCompanionAllMerchants(Page<CompanionAllMerchantsVo> page,CompanionAllMerchantsDTO dto);
+}

+ 89 - 0
nightFragrance-massage/src/main/java/com/ylx/companion/service/impl/CompanionRecommendServiceImpl.java

@@ -0,0 +1,89 @@
+package com.ylx.companion.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.companion.domain.dto.CompanionAllMerchantsDTO;
+import com.ylx.companion.domain.dto.CompanionRecommendDTO;
+import com.ylx.companion.domain.vo.CompanionAllMerchantsVo;
+import com.ylx.companion.domain.vo.ServiceCategoryVO;
+import com.ylx.companion.service.ICompanionRecommendService;
+import com.ylx.companion.domain.vo.CompanionRecommendVO;
+import com.ylx.companion.domain.vo.HotCompanionProjectVO;
+import com.ylx.massage.mapper.MaProjectMapper;
+import com.ylx.massage.mapper.MaTechnicianMapper;
+import com.ylx.servicecategory.domain.ServiceCategory;
+import com.ylx.servicecategory.mapper.ServiceCategoryMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 类描述:首页陪玩推荐
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/10 11:01
+ */
+@Service
+public class CompanionRecommendServiceImpl implements ICompanionRecommendService {
+    @Resource
+    private  MaTechnicianMapper technicianMapper;
+
+    @Resource
+    private MaProjectMapper maProjectMapper;
+    @Autowired
+    private ServiceCategoryMapper serviceCategoryMapper;
+    @Override
+    public CompanionRecommendVO getRecommend(CompanionRecommendDTO dto) {
+        CompanionRecommendVO vo = new CompanionRecommendVO();
+
+        // 1. 陪玩项目列表(type=2 且 上架状态)
+        vo.setServiceCategoryVoList(getCompanionProjects());
+
+        // 2. 热门陪玩商家(销量前五)
+        vo.setHotCompanionMerchantVoList(technicianMapper.getHotCompanionMerchantList(dto));
+
+        // 3. 热门陪玩项目(销量前五)
+        Page<HotCompanionProjectVO> page = new Page<>(dto.getPageNo(),dto.getPageSize());
+        vo.setHotCompanionProjectVoPage(maProjectMapper.getHotCompainonProjectList(page,dto.getCityCode(),dto.getCategoryId()));
+
+        return vo;
+    }
+
+    @Override
+    public Page<CompanionAllMerchantsVo> getCompanionAllMerchants(Page<CompanionAllMerchantsVo> page, CompanionAllMerchantsDTO dto) {
+        return maProjectMapper.getCompanionAllMerchants(page,dto);
+    }
+
+    /**
+     * 获取所有陪玩服务类目(转为 ServiceCategoryVO)
+     */
+    private List<ServiceCategoryVO> getCompanionProjects() {
+        LambdaQueryWrapper<ServiceCategory> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(ServiceCategory::getServiceTag, 2)
+                .eq(ServiceCategory::getIsOnline, 1)
+                .eq(ServiceCategory::getIsDelete, 0);
+        List<ServiceCategory> categories = serviceCategoryMapper.selectList(wrapper);
+        if (CollectionUtil.isEmpty(categories)) {
+            return new ArrayList<>();
+        }
+        return categories.stream().map(this::convertToServiceCategoryVO).collect(Collectors.toList());
+    }
+
+    /**
+     * 将 ServiceCategory 实体转换为 ServiceCategoryVO
+     */
+    private ServiceCategoryVO convertToServiceCategoryVO(ServiceCategory category) {
+        ServiceCategoryVO vo = new ServiceCategoryVO();
+        vo.setCategoryId(category.getId());
+        vo.setTitle(category.getName());
+        // 如果字段名不一致,可手动映射
+        return vo;
+    }
+}
+

+ 15 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaProjectMapper.java

@@ -4,6 +4,9 @@ import java.util.List;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.companion.domain.dto.CompanionAllMerchantsDTO;
+import com.ylx.companion.domain.vo.CompanionAllMerchantsVo;
+import com.ylx.companion.domain.vo.HotCompanionProjectVO;
 import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.dto.MassageAllMerchantsDto;
 import com.ylx.massage.domain.vo.MassageAllMerchantsVo;
@@ -71,7 +74,7 @@ public interface MaProjectMapper extends BaseMapper<MaProject> {
     public int deleteMaProjectByIds(String[] ids);
 
     /**
-     * 首页项目推荐
+     * 首页按摩项目推荐
      *
      * @param page
      * @return
@@ -86,4 +89,15 @@ public interface MaProjectMapper extends BaseMapper<MaProject> {
      */
     @Select("SELECT * FROM ma_project WHERE project_id = #{projectId} AND merchant_id = #{merchantId} AND is_delete = 0 LIMIT 1")
     MaProject selectByProjectIdAndMerchantId(@Param("projectId") Long projectId, @Param("merchantId") Long merchantId);
+
+    /**
+     * 根据城市编码查询热门陪玩项目列表
+     * @param page
+     * @param cityCode
+     * @return
+     */
+    Page<HotCompanionProjectVO> getHotCompainonProjectList(@Param("page") Page<HotCompanionProjectVO> page, @Param("cityCode") String cityCode, @Param("categoryId") Integer categoryId);
+
+    Page<CompanionAllMerchantsVo> getCompanionAllMerchants(@Param("page") Page<CompanionAllMerchantsVo> page, @Param("dto") CompanionAllMerchantsDTO dto);
+
 }

+ 10 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaTechnicianMapper.java

@@ -4,6 +4,8 @@ import java.util.List;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.companion.domain.dto.CompanionRecommendDTO;
+import com.ylx.companion.domain.vo.HotCompanionMerchantVO;
 import com.ylx.massage.domain.MaTechnician;
 import com.ylx.massage.domain.dto.MaTechnicianAuditQueryDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
@@ -193,4 +195,12 @@ public interface MaTechnicianMapper extends BaseMapper<MaTechnician>
             "      AND p.project_is_enable = 1" +
             ") AS has_merchant_with_service")
     Boolean isHasMerchantCity(@Param("areaCode")  String areaCode);
+
+    /**
+     * 首页陪玩热门商户推荐销量前五
+     * @param dto
+     * @return
+     */
+    List<HotCompanionMerchantVO> getHotCompanionMerchantList(@Param("dto") CompanionRecommendDTO dto);
 }
+

+ 0 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/service/IMaProjectService.java

@@ -13,7 +13,6 @@ import com.ylx.massage.domain.vo.MassageAllMerchantsVo;
 import com.ylx.massage.domain.vo.MassageProjectRecommendVo;
 import com.ylx.project.domain.bookMerchant.dto.BookMerchantDTO;
 import com.ylx.project.domain.bookMerchant.vo.BookMerchantVO;
-import org.apache.ibatis.annotations.Param;
 
 /**
  * 服务项目Service接口

+ 106 - 1
nightFragrance-massage/src/main/resources/mapper/massage/MaProjectMapper.xml

@@ -118,7 +118,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{id}
         </foreach>
     </delete>
-    <!-- 推荐项目-->
+    <!-- 首页按摩推荐项目-->
     <select id="getMassageProjectRecommend" resultType="com.ylx.massage.domain.vo.MassageProjectRecommendVo">
         SELECT
             pro.id                     AS projectId,
@@ -276,4 +276,109 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             </choose>
         </trim>
     </select>
+    <!-- 首页陪玩推荐项目-->
+    <select id="getHotCompainonProjectList" resultType="com.ylx.companion.domain.vo.HotCompanionProjectVO">
+        SELECT
+            pro.id                     AS projectId,
+            pro.title                  AS projectName,
+            pro.standard_duration      AS projectDuration,
+            COALESCE(ord.sales, 0)     AS sales,           -- 无订单时为 0
+            mp_avg.avgCurrentPrice,
+            pro.highlight              AS highlight
+        FROM project pro
+                 INNER JOIN (
+            -- 1. 符合条件的商家项目:按项目聚合,计算平均价格
+            SELECT
+                CAST(mp.project_id AS UNSIGNED) AS project_id,
+                AVG(mp.project_current_price)   AS avgCurrentPrice
+            FROM ma_project mp
+                     INNER JOIN ma_technician tech
+                                ON tech.id = CAST(mp.merchant_id AS UNSIGNED)
+                                    AND tech.te_area_code = #{cityCode}
+                                    AND tech.is_delete = 0
+                                    AND tech.audit_status = 2
+                                    AND tech.service_state = 1
+            WHERE mp.merchant_type = 2
+              AND mp.is_delete = 0
+              AND mp.project_is_enable = 1
+            GROUP BY CAST(mp.project_id AS UNSIGNED)
+        ) mp_avg ON mp_avg.project_id = pro.id
+                 LEFT JOIN (
+            -- 2. 订单统计:每个项目的真实订单数
+            SELECT
+                project_id,
+                COUNT(id) AS sales
+            FROM t_order
+            WHERE project_type = 2
+              AND status = 6
+              AND is_delete = 0
+            GROUP BY project_id
+        ) ord ON ord.project_id = pro.id
+        WHERE pro.is_delete = 0
+        <if test="categoryId != null">
+            AND pro.category_id = #{categoryId}
+        </if>
+        ORDER BY sales DESC, pro.id ASC
+    </select>
+
+    <!-- 首页陪玩推荐商户点击全部查询陪玩所有商户-->
+    <select id="getCompanionAllMerchants" resultType="com.ylx.companion.domain.vo.CompanionAllMerchantsVo">
+        SELECT
+        project_id AS projectId,
+        project_name AS projectName,
+        te_name AS merchantName,
+        id AS merchantId,
+        order_count AS nNum,   -- 子查询中已经 COALESCE 过了
+        CASE
+        WHEN #{dto.longitude} IS NOT NULL AND #{dto.latitude} IS NOT NULL THEN
+        CONCAT(
+        CASE WHEN distance_meters >= 1000 THEN ROUND(distance_meters / 1000.0, 1) ELSE distance_meters END,
+        CASE WHEN distance_meters >= 1000 THEN 'km' ELSE 'm' END
+        )
+        ELSE NULL
+        END AS distanceShow,
+        te_avatar AS teAvatar
+        FROM (
+        SELECT
+        p.project_id,
+        p.project_name,
+        t.te_name,
+        t.id,
+        t.te_avatar,
+        COALESCE(stat.order_count, 0) AS order_count,
+        ROUND(ST_Distance_Sphere(POINT(addr.longitude, addr.latitude), POINT(#{dto.longitude}, #{dto.latitude})), 0) AS distance_meters
+        FROM ma_technician t
+        INNER JOIN ma_project p
+        ON p.merchant_id = CAST(t.id AS CHAR)
+        AND p.audit_status = 1
+        AND p.is_delete = 0
+        AND p.merchant_type = 2
+        AND p.project_is_enable = 0
+        <if test="dto.projectId != null and dto.projectId != ''">
+            AND p.project_id = #{dto.projectId}
+        </if>
+        LEFT JOIN (
+        SELECT merchant_id, longitude, latitude
+        FROM t_address
+        WHERE user_type = 2 AND type = 1 AND is_delete = 0
+        ) addr ON t.id = addr.merchant_id
+        LEFT JOIN (
+        SELECT
+        merchant_id,
+        project_id,
+        COUNT(*) AS order_count
+        FROM t_order
+        WHERE status = 6
+        AND project_type = 2
+        AND is_delete = 0
+        GROUP BY merchant_id, project_id
+        ) stat ON stat.merchant_id = t.id AND stat.project_id = p.project_id
+        WHERE t.audit_status = 2
+        AND t.is_delete = 0
+        AND t.service_state = 1
+        AND t.te_area_code = #{dto.cityCode}
+        ) AS sub
+        ORDER BY nNum DESC  -- 或者 nNum DESC
+    </select>
+
 </mapper>

+ 50 - 0
nightFragrance-massage/src/main/resources/mapper/massage/MaTechnicianMapper.xml

@@ -515,5 +515,55 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             LIMIT 5
     </select>
 
+    <!-- 首页热门陪玩商户推荐列表-->
+    <select id="getHotCompanionMerchantList" resultType="com.ylx.companion.domain.vo.HotCompanionMerchantVO">
+        SELECT
+            t.id AS merchantId,
+            t.te_name AS merchantName,
+            t.n_star AS nStar,
+            COALESCE(o.sales, 0) AS nNum,
+            COALESCE(p.min_price, 0) AS price,
+            t.avatar AS avatar,
+            CASE
+                WHEN t.dist_meters IS NULL THEN NULL
+                WHEN t.dist_meters &lt; 1000 THEN CONCAT(ROUND(t.dist_meters, 0), 'm')
+                ELSE CONCAT(ROUND(t.dist_meters / 1000, 1), 'km')
+                END AS distanceShow
+        FROM (
+                 SELECT
+                     t.id,
+                     t.te_name,
+                     t.n_star,
+                     t.avatar,
+                     ROUND(ST_Distance_Sphere(POINT(a.longitude, a.latitude), POINT(#{dto.longitude}, #{dto.latitude})), 0) AS dist_meters
+                 FROM ma_technician t
+                          LEFT JOIN (
+                     SELECT merchant_id, longitude, latitude
+                     FROM t_address
+                     WHERE user_type = 2 AND type = 1 AND is_delete = 0
+                 ) a ON t.id = a.merchant_id
+                 WHERE t.is_delete = 0
+                   AND t.audit_status = 2
+                   AND t.n_status2 = 0
+                   AND t.merchant_status = 0
+                   AND t.te_area_code = #{dto.cityCode}
+             ) t
+                 LEFT JOIN (
+            SELECT merchant_id, COUNT(*) AS sales
+            FROM t_order
+            WHERE is_delete = 0 AND status = 6 AND project_type = 2
+            GROUP BY merchant_id
+        ) o ON t.id = o.merchant_id
+                 INNER JOIN (
+            SELECT merchant_id, MIN(project_current_price) AS min_price
+            FROM ma_project p
+            INNER JOIN project pt ON p.project_id = pt.id
+            WHERE is_delete = 0 AND audit_status = 1 AND merchant_type = 2 AND project_is_enable = 1
+            AND pt.category_id = #{dto.categoryId}   <!-- 通过 project 表关联 category_id -->
+            GROUP BY merchant_id
+        ) p ON t.id = p.merchant_id
+        ORDER BY COALESCE(o.sales, 0) DESC
+            LIMIT 5
+    </select>
 
 </mapper>