Parcourir la source

feat(applet): 实现用户端分页查询站点信息功能

- 新增StationInfoQuery用于封装查询参数,支持经纬度及排序类型
- 创建StationInfoVO作为小程序首页站点信息视图对象
- 在AppletHomeService接口及实现类中添加getStationInfoPage方法实现分页查询逻辑
- 查询时通过当前登录用户判断是否企业用户,获取企业ID以标识用户类型
- Mapper层新增selectAppletStationInfoPage SQL,支持根据距离、价格等多维度排序
- SQL中关联政策费用表确保只返回已配置政策费的站点,计算快充数量及当前峰值时段
- Controller增加对应接口,提供REST接口供小程序调用
- 修改主键生成策略为ASSIGN_ID,优化实体类ID定义
- 对应VO和映射配置添加销售类型、企业ID及渠道方ID字段支持更丰富数据返回
SheepHy il y a 1 jour
Parent
commit
5c2dacb909

+ 23 - 0
src/main/java/com/zsElectric/boot/business/controller/applet/AppletHomeController.java

@@ -1,7 +1,15 @@
 package com.zsElectric.boot.business.controller.applet;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.zsElectric.boot.business.model.query.StationInfoQuery;
+import com.zsElectric.boot.business.model.vo.StationInfoVO;
+import com.zsElectric.boot.business.service.AppletHomeService;
+import com.zsElectric.boot.core.web.PageResult;
+import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.RequiredArgsConstructor;
+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;
 
@@ -10,4 +18,19 @@ import org.springframework.web.bind.annotation.RestController;
 @RequestMapping("/applet/v1/home")
 @RequiredArgsConstructor
 public class AppletHomeController {
+
+    private final AppletHomeService appletHomeService;
+
+    /**
+     * 用户端分页查询站点信息
+     *
+     * @param queryParams 查询参数
+     * @return 站点信息分页列表
+     */
+    @Operation(summary = "用户端分页查询站点信息")
+    @PostMapping("/getStationInfoPage")
+    public PageResult<StationInfoVO> getStationInfoPage(@RequestBody StationInfoQuery queryParams) {
+        IPage<StationInfoVO> result = appletHomeService.getStationInfoPage(queryParams);
+        return PageResult.success(result);
+    }
 }

+ 19 - 0
src/main/java/com/zsElectric/boot/business/mapper/ThirdPartyStationInfoMapper.java

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.zsElectric.boot.charging.entity.ThirdPartyStationInfo;
+import com.zsElectric.boot.business.model.query.StationInfoQuery;
+import com.zsElectric.boot.business.model.vo.StationInfoVO;
 import com.zsElectric.boot.business.model.query.ThirdPartyStationInfoQuery;
 import com.zsElectric.boot.business.model.vo.ThirdPartyStationInfoVO;
 import org.apache.ibatis.annotations.Mapper;
@@ -35,4 +37,21 @@ public interface ThirdPartyStationInfoMapper extends BaseMapper<ThirdPartyStatio
      * @return 充电站信息分页列表
      */
     IPage<ThirdPartyStationInfoVO> selectStationInfoPageByEquipment(Page<ThirdPartyStationInfoVO> page, @Param("query") ThirdPartyStationInfoQuery query);
+
+    /**
+     * 小程序首页分页查询站点信息
+     * 只返回已配置PolicyFee的站点
+     *
+     * @param page 分页对象
+     * @param query 查询条件
+     * @param currentTime 当前时间(HHmmss格式)
+     * @param firmId 企业ID(可为null)
+     * @return 站点信息分页列表
+     */
+    IPage<StationInfoVO> selectAppletStationInfoPage(
+            Page<StationInfoVO> page,
+            @Param("query") StationInfoQuery query,
+            @Param("currentTime") String currentTime,
+            @Param("firmId") Long firmId
+    );
 }

+ 1 - 1
src/main/java/com/zsElectric/boot/business/model/entity/PolicyFee.java

@@ -32,7 +32,7 @@ public class PolicyFee implements Serializable {
     /**
      * 主键ID
      */
-    @TableId(type = IdType.AUTO)
+    @TableId(type = IdType.ASSIGN_ID)
     private Long id;
 
     /**

+ 38 - 0
src/main/java/com/zsElectric/boot/business/model/query/StationInfoQuery.java

@@ -0,0 +1,38 @@
+package com.zsElectric.boot.business.model.query;
+
+import com.zsElectric.boot.common.base.BasePageQuery;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/**
+ * 小程序首页站点信息查询对象
+ *
+ * @author system
+ * @since 2025-12-16
+ */
+@Schema(description = "小程序首页站点信息查询对象")
+@Getter
+@Setter
+public class StationInfoQuery extends BasePageQuery {
+
+    /**
+     * 请求类别:1-离我最近、2-空闲最多、3-电费最低
+     */
+    @Schema(description = "请求类别:1-离我最近、2-空闲最多、3-电费最低")
+    private Integer sortType;
+
+    /**
+     * 经度
+     */
+    @Schema(description = "经度")
+    private BigDecimal longitude;
+
+    /**
+     * 纬度
+     */
+    @Schema(description = "纬度")
+    private BigDecimal latitude;
+}

+ 54 - 0
src/main/java/com/zsElectric/boot/business/model/vo/StationInfoVO.java

@@ -0,0 +1,54 @@
+package com.zsElectric.boot.business.model.vo;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 小程序首页站点信息视图对象
+ *
+ * @author system
+ * @since 2025-12-16
+ */
+@Getter
+@Setter
+@Schema(description = "小程序首页站点信息视图对象")
+public class StationInfoVO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "站点ID")
+    private Long stationId;
+
+    @Schema(description = "站点名称")
+    private String stationName;
+
+    @Schema(description = "提示语")
+    private String tips;
+
+    @Schema(description = "距离(km)")
+    private BigDecimal distance;
+
+    @Schema(description = "快充(格式:空闲/总数)")
+    private String fastCharging;
+
+    @Schema(description = "慢充(格式:空闲/总数)")
+    private String slowCharging;
+
+    @Schema(description = "峰值")
+    private String peakValue;
+
+    @Schema(description = "平台价")
+    private BigDecimal platformPrice;
+
+    @Schema(description = "企业价")
+    private BigDecimal enterprisePrice;
+
+    @Schema(description = "是否企业用户(true-是 false-否)")
+    private Boolean firmUser;
+}

+ 9 - 0
src/main/java/com/zsElectric/boot/business/model/vo/ThirdPartyStationInfoVO.java

@@ -62,6 +62,15 @@ public class ThirdPartyStationInfoVO {
     @Schema(description = "站点提示语")
     private String stationTips;
 
+    @Schema(description = "销售类型(0-平台 1-企业 2-渠道方)")
+    private Integer salesType;
+
+    @Schema(description = "企业ID(销售类型为1时有值)")
+    private Long firmId;
+
+    @Schema(description = "渠道方ID(销售类型为2时有值)")
+    private Long thirdPartyId;
+
     @Schema(description = "电费")
     private BigDecimal electricityFee;
 

+ 6 - 0
src/main/java/com/zsElectric/boot/business/model/vo/TimePeriodPriceVO.java

@@ -47,4 +47,10 @@ public class TimePeriodPriceVO implements Serializable {
 
     @Schema(description = "时段标志(1-尖,2-峰,3-平,4-谷)")
     private Integer periodFlag;
+
+    @Schema(description = "企业ID(销售类型为1时有值)")
+    private Long firmId;
+
+    @Schema(description = "渠道方ID(销售类型为2时有值)")
+    private Long thirdPartyId;
 }

+ 9 - 0
src/main/java/com/zsElectric/boot/business/service/AppletHomeService.java

@@ -1,4 +1,13 @@
 package com.zsElectric.boot.business.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.zsElectric.boot.business.model.query.StationInfoQuery;
+import com.zsElectric.boot.business.model.vo.StationInfoVO;
+
 public interface AppletHomeService {
+
+    /**
+     * 用户端分页查询站点信息
+     * */
+    IPage<StationInfoVO> getStationInfoPage(StationInfoQuery queryParams);
 }

+ 60 - 0
src/main/java/com/zsElectric/boot/business/service/impl/AppletHomeServiceImpl.java

@@ -1,10 +1,70 @@
 package com.zsElectric.boot.business.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zsElectric.boot.business.mapper.ThirdPartyStationInfoMapper;
+import com.zsElectric.boot.business.mapper.UserFirmMapper;
+import com.zsElectric.boot.business.model.entity.UserFirm;
+import com.zsElectric.boot.business.model.query.StationInfoQuery;
+import com.zsElectric.boot.business.model.vo.StationInfoVO;
 import com.zsElectric.boot.business.service.AppletHomeService;
+import com.zsElectric.boot.security.util.SecurityUtils;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+@Slf4j
 @Service
 @RequiredArgsConstructor
 public class AppletHomeServiceImpl implements AppletHomeService {
+
+    private final ThirdPartyStationInfoMapper thirdPartyStationInfoMapper;
+    private final UserFirmMapper userFirmMapper;
+
+    /**
+     * 时间格式化器 HHmmss
+     */
+    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HHmmss");
+
+    @Override
+    public IPage<StationInfoVO> getStationInfoPage(StationInfoQuery queryParams) {
+        // 获取当前登录用户ID
+        Long userId = SecurityUtils.getUserId();
+        
+        // 查询用户是否为企业用户,获取企业ID
+        Long firmId = null;
+        boolean isFirmUser = false;
+        if (userId != null) {
+            UserFirm userFirm = userFirmMapper.selectOne(
+                    new LambdaQueryWrapper<UserFirm>()
+                            .eq(UserFirm::getUserId, userId)
+                            .last("LIMIT 1")
+            );
+            if (userFirm != null) {
+                firmId = userFirm.getFirmId();
+                isFirmUser = true;
+            }
+        }
+        
+        // 获取当前时间(HHmmss格式)
+        String currentTime = LocalTime.now().format(TIME_FORMATTER);
+        
+        // 构建分页对象
+        Page<StationInfoVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
+        
+        // 执行查询
+        IPage<StationInfoVO> resultPage = thirdPartyStationInfoMapper.selectAppletStationInfoPage(
+                page, queryParams, currentTime, firmId
+        );
+        
+        // 设置是否企业用户标识
+        final boolean finalIsFirmUser = isFirmUser;
+        resultPage.getRecords().forEach(vo -> vo.setFirmUser(finalIsFirmUser));
+        
+        return resultPage;
+    }
 }

+ 154 - 2
src/main/resources/mapper/business/ThirdPartyStationInfoMapper.xml

@@ -18,6 +18,9 @@
         <result property="stationLat" column="station_lat"/>
         <result property="siteGuide" column="site_guide"/>
         <result property="stationTips" column="station_tips"/>
+        <result property="salesType" column="sales_type"/>
+        <result property="firmId" column="firm_id"/>
+        <result property="thirdPartyId" column="third_party_id"/>
     </resultMap>
 
     <select id="selectStationInfoPage" resultMap="StationInfoResultMap">
@@ -80,9 +83,24 @@
             tpsi.station_lng,
             tpsi.station_lat,
             tpsi.site_guide,
-            tpsi.station_tips
+            tpsi.station_tips,
+            CASE
+                WHEN pf.firm_id IS NOT NULL THEN 1
+                WHEN pf.third_party_id IS NOT NULL THEN 2
+                ELSE 0
+            END AS sales_type,
+            pf.firm_id,
+            pf.third_party_id
         FROM third_party_station_info tpsi
         LEFT JOIN third_party_equipment_info tpei ON tpsi.station_id = tpei.station_id AND tpei.is_deleted = 0
+        LEFT JOIN (
+            SELECT station_info_id, firm_id, third_party_id,
+                ROW_NUMBER() OVER (PARTITION BY station_info_id, 
+                    CASE WHEN firm_id IS NOT NULL THEN 1 WHEN third_party_id IS NOT NULL THEN 2 ELSE 0 END 
+                    ORDER BY id) AS rn
+            FROM c_policy_fee
+            WHERE is_deleted = 0
+        ) pf ON pf.station_info_id = tpsi.id AND pf.rn = 1
         WHERE tpsi.is_deleted = 0
         AND tpsi.equipment_owner_id = 'MA6DP6BE7'
         AND tpsi.policy_configured = 1
@@ -107,8 +125,142 @@
         <if test="query.serviceTel != null and query.serviceTel != ''">
             AND tpsi.service_tel = #{query.serviceTel}
         </if>
-        GROUP BY tpsi.id
+        GROUP BY tpsi.id, pf.firm_id, pf.third_party_id
         ORDER BY tpsi.update_time DESC
     </select>
 
+    <!-- 小程序首页站点信息查询结果映射 -->
+    <resultMap id="AppletStationInfoResultMap" type="com.zsElectric.boot.business.model.vo.StationInfoVO">
+        <result property="stationId" column="station_info_id"/>
+        <result property="stationName" column="station_name"/>
+        <result property="tips" column="station_tips"/>
+        <result property="distance" column="distance"/>
+        <result property="fastCharging" column="fast_charging"/>
+        <result property="slowCharging" column="slow_charging"/>
+        <result property="peakValue" column="peak_value"/>
+        <result property="platformPrice" column="platform_price"/>
+        <result property="enterprisePrice" column="enterprise_price"/>
+    </resultMap>
+
+    <!-- 小程序首页分页查询站点信息 -->
+    <select id="selectAppletStationInfoPage" resultMap="AppletStationInfoResultMap">
+        SELECT
+            tpsi.id AS station_info_id,
+            tpsi.station_name,
+            tpsi.station_tips,
+            <!-- 计算距离(km) -->
+            <if test="query.longitude != null and query.latitude != null">
+                ROUND(
+                    6371 * ACOS(
+                        COS(RADIANS(#{query.latitude})) * COS(RADIANS(tpsi.station_lat))
+                        * COS(RADIANS(tpsi.station_lng) - RADIANS(#{query.longitude}))
+                        + SIN(RADIANS(#{query.latitude})) * SIN(RADIANS(tpsi.station_lat))
+                    ), 2
+                ) AS distance,
+            </if>
+            <if test="query.longitude == null or query.latitude == null">
+                NULL AS distance,
+            </if>
+            <!-- 快充统计(空闲/总数) -->
+            CONCAT(
+                COUNT(tpci.id),
+                '/',
+                COUNT(tpci.id)
+            ) AS fast_charging,
+            <!-- 慢充统计(直接0/0) -->
+            '0/0' AS slow_charging,
+            <!-- 峰值(根据当前时段获取) -->
+            (
+                SELECT
+                    CASE tppi.period_flag
+                        WHEN 1 THEN '尖'
+                        WHEN 2 THEN '峰'
+                        WHEN 3 THEN '平'
+                        WHEN 4 THEN '谷'
+                        ELSE ''
+                    END
+                FROM third_party_policy_info tppi
+                INNER JOIN third_party_equipment_price_policy tpepp ON tppi.price_policy_id = tpepp.id AND tpepp.is_deleted = 0
+                INNER JOIN third_party_equipment_info tpei2 ON tpepp.equipment_id = tpei2.equipment_id AND tpei2.is_deleted = 0
+                WHERE tpei2.station_id = tpsi.station_id
+                    AND tppi.is_deleted = 0
+                    AND tppi.start_time &lt;= #{currentTime}
+                ORDER BY tppi.start_time DESC
+                LIMIT 1
+            ) AS peak_value,
+            <!-- 平台价(电费+服务费+运营费+综合销售费) -->
+            (
+                SELECT
+                    ROUND(
+                        IFNULL(tppi.elec_price, 0) + IFNULL(tppi.service_price, 0)
+                        + IFNULL(pf.op_fee, 0) + IFNULL(pf.comp_sales_fee, 0),
+                        4
+                    )
+                FROM c_policy_fee pf
+                INNER JOIN third_party_policy_info tppi ON pf.start_time = tppi.start_time
+                INNER JOIN third_party_equipment_price_policy tpepp ON tppi.price_policy_id = tpepp.id AND tpepp.is_deleted = 0
+                INNER JOIN third_party_equipment_info tpei3 ON tpepp.equipment_id = tpei3.equipment_id AND tpei3.is_deleted = 0
+                WHERE tpei3.station_id = tpsi.station_id
+                    AND pf.station_info_id = tpsi.id
+                    AND pf.sales_type = 0
+                    AND pf.is_deleted = 0
+                    AND tppi.is_deleted = 0
+                    AND pf.start_time &lt;= #{currentTime}
+                ORDER BY pf.start_time DESC
+                LIMIT 1
+            ) AS platform_price,
+            <!-- 企业价(如果有企业ID) -->
+            <if test="firmId != null">
+            (
+                SELECT
+                    ROUND(
+                        IFNULL(tppi.elec_price, 0) + IFNULL(tppi.service_price, 0)
+                        + IFNULL(pf.op_fee, 0) + IFNULL(pf.comp_sales_fee, 0),
+                        4
+                    )
+                FROM c_policy_fee pf
+                INNER JOIN third_party_policy_info tppi ON pf.start_time = tppi.start_time
+                INNER JOIN third_party_equipment_price_policy tpepp ON tppi.price_policy_id = tpepp.id AND tpepp.is_deleted = 0
+                INNER JOIN third_party_equipment_info tpei4 ON tpepp.equipment_id = tpei4.equipment_id AND tpei4.is_deleted = 0
+                WHERE tpei4.station_id = tpsi.station_id
+                    AND pf.station_info_id = tpsi.id
+                    AND pf.sales_type = 1
+                    AND pf.firm_id = #{firmId}
+                    AND pf.is_deleted = 0
+                    AND tppi.is_deleted = 0
+                    AND pf.start_time &lt;= #{currentTime}
+                ORDER BY pf.start_time DESC
+                LIMIT 1
+            ) AS enterprise_price
+            </if>
+            <if test="firmId == null">
+            NULL AS enterprise_price
+            </if>
+        FROM third_party_station_info tpsi
+        LEFT JOIN third_party_connector_info tpci ON tpsi.station_id = tpci.station_id AND tpci.is_deleted = 0
+        WHERE tpsi.is_deleted = 0
+            AND tpsi.equipment_owner_id = 'MA6DP6BE7'
+            AND tpsi.policy_configured = 1
+            <!-- 确保存在平台价配置 -->
+            AND EXISTS (
+                SELECT 1 FROM c_policy_fee pf_check
+                WHERE pf_check.station_info_id = tpsi.id
+                    AND pf_check.sales_type = 0
+                    AND pf_check.is_deleted = 0
+                    AND (pf_check.op_fee IS NOT NULL OR pf_check.comp_sales_fee IS NOT NULL)
+            )
+        GROUP BY tpsi.id
+        <if test="query.sortType != null">
+            <if test="query.sortType == 1 and query.longitude != null and query.latitude != null">
+                ORDER BY distance ASC
+            </if>
+            <if test="query.sortType == 3">
+                ORDER BY platform_price ASC
+            </if>
+        </if>
+        <if test="query.sortType == null or (query.sortType == 1 and (query.longitude == null or query.latitude == null))">
+            ORDER BY tpsi.update_time DESC
+        </if>
+    </select>
+
 </mapper>