xuhy
2025-07-22 ed8a37dcf91881fde24155bfbe76a8d59d201e4b
充电服务
4个文件已修改
95个文件已添加
7107 ■■■■■ 已修改文件
pom.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/pom.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/ApplyChargingQuery.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/ApplyChargingRemarkDto.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/CheckChargingStrategyDTO.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/GetPermissionConfigurationDTO.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/GetSiteListDTO.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/PageChargingPileListDTO.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/PartnerListDTO.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/TAccountingStrategyDTO.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/TAccountingStrategyDetailDTO.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/TChargingGunDTO.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/AccountingStrategyDetailFallbackFactory.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/AccountingStrategyFallbackFactory.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/ChargingGunFallbackFactory.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/ChargingPileFallbackFactory.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/SiteFallbackFactory.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/AccountingStrategyClient.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/AccountingStrategyDetailClient.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/ChargingGunClient.java 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/ChargingPileClient.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/SiteClient.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/Site.java 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TAccountingStrategy.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TAccountingStrategyDetail.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TChargingGun.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TChargingPile.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/BatchSetAccountingStrategy.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/GetPartnerList.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/GetSiteList.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/PageChargingPileList.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/ParkingRecordQuery.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/SetPermissionConfiguration.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/SiteDetailQuery.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/SiteQuery.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TAccountingStrategyQuery.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TChargingGunQuery.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TMonitoringEquipmentQuery.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TParkingLotQuery.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TVehicleRampQuery.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/ChargingGunCountVO.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/GetChargingGunByCode.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/GetParkingRecord.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/GunStatusStatisticsVO.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteDetailVO.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteInfoVO.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteNameVO.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteVO.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/StatusModeStatisticsVO.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/StrategyPriceVO.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TAccountingStrategyDetailVO.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TAccountingStrategyVO.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingPileVO.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/UpdateChargingPileStatusVo.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/resources/template/充电桩申请记录.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/pom.xml 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/RuoYiChargingPileApplication.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/DataUpdateHandlerConfig.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/FileUploadConfig.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/HttpConfig.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/MybatisPlusConfig.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java 258 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java 382 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyDetailController.java 231 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java 333 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ResetPassword.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/SiteDTO.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/SiteMapper.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TAccountingStrategyDetailMapper.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TAccountingStrategyMapper.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TChargingGunMapper.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TChargingPileMapper.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/ISiteService.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TAccountingStrategyDetailService.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TAccountingStrategyService.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java 291 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TAccountingStrategyDetailServiceImpl.java 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TAccountingStrategyServiceImpl.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java 312 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/util/QRCodeUtils.java 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/util/TaskUtil.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/bootstrap.yml 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/logback.xml 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml 322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TAccountingStrategyDetailMapper.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TAccountingStrategyMapper.xml 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingPileMapper.xml 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mybatis-config.xml 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/RuoYiChargingPileApplicationTests.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -219,7 +219,13 @@
                <artifactId>ruoyi-api-other</artifactId>
                <version>${ruoyi.version}</version>
            </dependency>
            <!-- 系统其他接口 -->
            <dependency>
                <groupId>com.ruoyi</groupId>
                <artifactId>ruoyi-api-chargingPile</artifactId>
                <version>${ruoyi.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
ruoyi-api/pom.xml
@@ -13,6 +13,7 @@
        <module>ruoyi-api-account</module>
        <module>ruoyi-api-order</module>
        <module>ruoyi-api-other</module>
        <module>ruoyi-api-chargingPile</module>
    </modules>
    <artifactId>ruoyi-api</artifactId>
ruoyi-api/ruoyi-api-chargingPile/pom.xml
New file
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.ruoyi</groupId>
        <artifactId>ruoyi-api</artifactId>
        <version>3.6.2</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>ruoyi-api-chargingPile</artifactId>
    <description>
        ruoyi-api-chargingPile充电桩接口模块
    </description>
    <dependencies>
        <!-- RuoYi Common Core-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-common-core</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.github.pagehelper</groupId>
                    <artifactId>pagehelper-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/ApplyChargingQuery.java
New file
@@ -0,0 +1,9 @@
package com.ruoyi.chargingPile.api.dto;
import com.ruoyi.common.core.web.page.BasePage;
import lombok.Data;
@Data
public class ApplyChargingQuery extends BasePage {
    String landlordPhone;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/ApplyChargingRemarkDto.java
New file
@@ -0,0 +1,10 @@
package com.ruoyi.chargingPile.api.dto;
import com.ruoyi.common.core.web.page.BasePage;
import lombok.Data;
@Data
public class ApplyChargingRemarkDto extends BasePage {
    Integer id;
    String remark;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/CheckChargingStrategyDTO.java
New file
@@ -0,0 +1,19 @@
package com.ruoyi.chargingPile.api.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "校验计费模版是否准确DTO")
public class CheckChargingStrategyDTO implements Serializable {
    @ApiModelProperty(value = "桩编号code")
    private String code;
    @ApiModelProperty(value = "计费模型编号  id")
    private Integer strategyDetailId;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/GetPermissionConfigurationDTO.java
New file
@@ -0,0 +1,21 @@
package com.ruoyi.chargingPile.api.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
 * @author zhibing.pu
 * @Date 2024/8/9 10:30
 */
@Data
@ApiModel
public class GetPermissionConfigurationDTO {
    @ApiModelProperty(value = "备注")
    private String permissionRemarks;
    @ApiModelProperty(value = "权限菜单")
    private List<Map<String, Object>> menu;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/GetSiteListDTO.java
New file
@@ -0,0 +1,77 @@
package com.ruoyi.chargingPile.api.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author zhibing.pu
 * @Date 2024/8/8 9:29
 */
@Data
@ApiModel
public class GetSiteListDTO {
    @ApiModelProperty(value = "站点id")
    private Integer id;
    @ApiModelProperty(value = "站点编号")
    private String code;
    @ApiModelProperty(value = "站点名称")
    private String name;
    @ApiModelProperty(value = "合作商id")
    private Integer partnerId;
    @ApiModelProperty(value = "合作商名称")
    private String partnerName;
    @ApiModelProperty(value = "站点类型(0=其他,1=公共,2=个人,3=公交(专业),4=环卫(专用),5=物流(专用),6=出租车(专用))")
    private Integer siteType;
    @ApiModelProperty(value = "经营类型(1=直营,2=非直营)")
    private Integer businessCategory;
    @ApiModelProperty(value = "站点状态(1=正常使用,2=维修中,3=关闭下线)")
    private Integer status;
    @ApiModelProperty(value = "详细地址")
    private String address;
    @ApiModelProperty(value = "站点电话")
    private String phone;
    @ApiModelProperty(value = "lon")
    private String lon;
    @ApiModelProperty(value = "lat")
    private String lat;
    @ApiModelProperty(value = "服务电话")
    private String servicePhone;
    @ApiModelProperty(value = "车位数")
    private Integer parkingSpace;
    @ApiModelProperty(value = "建站时间")
    private String establishmentTime;
    @ApiModelProperty(value = "充电桩数量")
    private Integer chargingPileNumber;
    @ApiModelProperty(value = "排序")
    private Integer sort;
    @ApiModelProperty("计费策略id")
    private Integer accountingStrategyId;
    @ApiModelProperty("计费策略类型(1=平台添加,2=自定义策略)")
    private Integer accountingStrategyType;
    @ApiModelProperty(value = "计费策略权限")
    private boolean authAccountingStrategy = true;
    @ApiModelProperty(value = "合作商权限")
    private boolean authPartner = true;
    @ApiModelProperty(value = "编辑权限")
    private boolean authUpdate = true;
    @ApiModelProperty(value = "删除权限")
    private boolean authDelete = true;
    @ApiModelProperty("超1")
    private Long c1;
    @ApiModelProperty("超2")
    private Long c2;
    @ApiModelProperty("快1")
    private Long k1;
    @ApiModelProperty("快2")
    private Long k2;
    @ApiModelProperty("慢1")
    private Long m1;
    @ApiModelProperty("慢2")
    private Long m2;
    @ApiModelProperty("利用率")
    private BigDecimal p1;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/PageChargingPileListDTO.java
New file
@@ -0,0 +1,49 @@
package com.ruoyi.chargingPile.api.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author zhibing.pu
 * @Date 2024/8/8 15:07
 */
@Data
@ApiModel
public class PageChargingPileListDTO {
    @ApiModelProperty(value = "充电桩id")
    private Integer id;
    @ApiModelProperty(value = "充电桩编号")
    private String code;
    @ApiModelProperty(value = "充电桩名称")
    private String name;
    @ApiModelProperty(value = "桩号")
    private String number;
    @ApiModelProperty(value = "设备类型(0=其他,1=直流设备,2=交流设备,3=交直流一体设备,4=无线设备)")
    private Integer type;
    @ApiModelProperty(value = "归属电站id")
    private Integer siteId;
    @ApiModelProperty(value = "归属电站名称")
    private String siteName;
    @ApiModelProperty(value = "归属合作商id")
    private String partnerId;
    @ApiModelProperty(value = "归属合作商名称")
    private String partnerName;
    @ApiModelProperty(value = "生产商名称")
    private String manufacturer;
    @ApiModelProperty(value = "设备型号")
    private String equipmentType;
    @ApiModelProperty(value = "额定功率")
    private BigDecimal ratedPower;
    @ApiModelProperty(value = "查看权限")
    private boolean authQueryInfo = true;
    @ApiModelProperty(value = "编辑权限")
    private boolean authUpdate = true;
    @ApiModelProperty(value = "删除权限")
    private boolean authDelete = true;
    @ApiModelProperty(value = "新增接口权限")
    private boolean authAddChargingGun = true;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/PartnerListDTO.java
New file
@@ -0,0 +1,29 @@
package com.ruoyi.chargingPile.api.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 14:03
 */
@Data
@ApiModel
public class PartnerListDTO {
    @ApiModelProperty(value = "数据id")
    private Integer id;
    @ApiModelProperty(value = "合作商名称")
    private String name;
    private Integer roleId;
    @ApiModelProperty(value = "角色名")
    private String roleName;
    @ApiModelProperty(value = "合作商电话1")
    private String phoneOne;
    @ApiModelProperty(value = "注册地址")
    private String address;
    @ApiModelProperty(value = "登录账号")
    private String account;
    @ApiModelProperty(value = "备注")
    private String remark;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/TAccountingStrategyDTO.java
New file
@@ -0,0 +1,18 @@
package com.ruoyi.chargingPile.api.dto;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value="TAccountingStrategyDTO对象", description="计费策略")
public class TAccountingStrategyDTO extends TAccountingStrategy {
    @ApiModelProperty(value = "计费策略明细")
    private List<TAccountingStrategyDetail> accountingStrategyDetails;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/TAccountingStrategyDetailDTO.java
New file
@@ -0,0 +1,10 @@
package com.ruoyi.chargingPile.api.dto;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel(value="TAccountingStrategyDetailDTO对象", description="计费策略明细")
public class TAccountingStrategyDetailDTO extends TAccountingStrategyDetail {
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/dto/TChargingGunDTO.java
New file
@@ -0,0 +1,12 @@
package com.ruoyi.chargingPile.api.dto;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel(value="TChargingGunDTO对象", description="充电枪")
public class TChargingGunDTO extends TChargingGun {
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/AccountingStrategyDetailFallbackFactory.java
New file
@@ -0,0 +1,54 @@
package com.ruoyi.chargingPile.api.factory;
import com.ruoyi.chargingPile.api.dto.CheckChargingStrategyDTO;
import com.ruoyi.chargingPile.api.feignClient.AccountingStrategyDetailClient;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import com.ruoyi.common.core.domain.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/28 18:33
 */
@Component
public class AccountingStrategyDetailFallbackFactory  implements FallbackFactory<AccountingStrategyDetailClient> {
    private static final Logger log = LoggerFactory.getLogger(AccountingStrategyDetailFallbackFactory.class);
    @Override
    public AccountingStrategyDetailClient create(Throwable throwable) {
        log.error("计费策略调用失败:{}", throwable.getMessage());
        return new AccountingStrategyDetailClient(){
            @Override
            public R<TAccountingStrategyDetail> getDetailBySiteId(Integer siteId) {
                return R.fail("通过站点id查询当前时段使用的策略明细失败:" + throwable.getMessage());
            }
            @Override
            public R<TAccountingStrategyDetail> getDetailByCode(String code) {
                return R.fail("通过桩编号查询当前时段使用的策略明细失败:" + throwable.getMessage());
            }
            @Override
            public R<Boolean> checkChargingStrategy(CheckChargingStrategyDTO dto) {
                return R.fail("校验充电桩计费模版是否准确失败:" + throwable.getMessage());
            }
            @Override
            public R<List<TAccountingStrategyDetail>> getListByAccountingStrategyId(Integer id) {
                return R.fail("根据计费策略主表id策略明细失败:" + throwable.getMessage());
            }
            @Override
            public R<List<TAccountingStrategyDetail>> getDetailListByCode(String code) {
                return R.fail("通过桩编号查询当前使用的策略明细列表失败:" + throwable.getMessage());
            }
        };
    }
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/AccountingStrategyFallbackFactory.java
New file
@@ -0,0 +1,32 @@
package com.ruoyi.chargingPile.api.factory;
import com.ruoyi.chargingPile.api.feignClient.AccountingStrategyClient;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.common.core.domain.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
 * @author zhibing.pu
 * @Date 2024/8/28 18:33
 */
@Component
public class AccountingStrategyFallbackFactory implements FallbackFactory<AccountingStrategyClient> {
    private static final Logger log = LoggerFactory.getLogger(AccountingStrategyFallbackFactory.class);
    @Override
    public AccountingStrategyClient create(Throwable throwable) {
        log.error("计费策略调用失败:{}", throwable.getMessage());
        return new AccountingStrategyClient(){
            @Override
            public R<TAccountingStrategy> getAccountingStrategyById(Integer id) {
                return R.fail("根据id查询计费策略失败:" + throwable.getMessage());
            }
        };
    }
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/ChargingGunFallbackFactory.java
New file
@@ -0,0 +1,92 @@
package com.ruoyi.chargingPile.api.factory;
import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.vo.GetChargingGunByCode;
import com.ruoyi.chargingPile.api.vo.SiteNameVO;
import com.ruoyi.common.core.domain.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
/**
 * 充电桩服务降级处理
 *
 * @author ruoyi
 */
@Component
public class ChargingGunFallbackFactory implements FallbackFactory<ChargingGunClient>
{
    private static final Logger log = LoggerFactory.getLogger(ChargingGunFallbackFactory.class);
    @Override
    public ChargingGunClient create(Throwable throwable) {
        log.error("充电枪调用失败:{}", throwable.getMessage());
        return new ChargingGunClient() {
            @Override
            public R<List<TChargingGun>> getAllGun() {
                return R.fail("获取数据失败:" + throwable.getMessage());
            }
            @Override
            public R<List<TChargingPile>> getAllPile() {
                return R.fail("获取所有桩失败:" + throwable.getMessage());
            }
            @Override
            public R<String> getAllName(Integer id) {
                return R.fail("根据id获取充电枪完整名称失败:" + throwable.getMessage());
            }
            @Override
            public R<TChargingGun> getChargingGunById(Integer id) {
                return R.fail("根据id获取充电枪失败:" + throwable.getMessage());
            }
            @Override
            public R<SiteNameVO> getAllInfoById(Integer id) {
                return R.fail("通过枪id获取站点、桩、枪的名称失败:" + throwable.getMessage());
            }
            @Override
            public R<TChargingGun> getChargingGunByCode(GetChargingGunByCode code) {
                return R.fail("根据枪编号获取充电枪失败:" + throwable.getMessage());
            }
            @Override
            public R<String> updateChargingGunById(TChargingGun chargingGun) {
                return R.fail("编辑充电枪失败:" + throwable.getMessage());
            }
            @Override
            public R<List<TChargingGun>> getChargingGunByChargingPileId(Integer chargingPileId) {
                return R.fail("根据充电桩id获取枪失败:" + throwable.getMessage());
            }
            @Override
            public R<List<TChargingGun>> getChargingGunByChargingPileIds(List<Integer> chargingPileIds) {
                return R.fail("根据充电桩ids获取枪失败:" + throwable.getMessage());
            }
            @Override
            public R pushChargingGunStatus(Integer id, Integer status) {
                return R.fail("接口状态变化后推送给第三方失败:" + throwable.getMessage());
            }
            @Override
            public R<TChargingGun> getChargingGunByFullNumber(String fullNumber) {
                return R.fail("根据枪唯一码查询信息失败:" + throwable.getMessage());
            }
            @Override
            public R<List<Integer>> getGunIdsBySiteIdsAndChargeModels(List<Integer> siteIds, List<Integer> chargeModels){
                return R.fail("根据站点ids和充电模式集合查询充电枪集合失败:" + throwable.getMessage());
            }
        };
    }
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/ChargingPileFallbackFactory.java
New file
@@ -0,0 +1,68 @@
package com.ruoyi.chargingPile.api.factory;
import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.vo.SiteInfoVO;
import com.ruoyi.chargingPile.api.vo.UpdateChargingPileStatusVo;
import com.ruoyi.common.core.domain.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.List;
/**
 * 充电桩服务降级处理
 *
 * @author ruoyi
 */
@Component
public class ChargingPileFallbackFactory implements FallbackFactory<ChargingPileClient>
{
    private static final Logger log = LoggerFactory.getLogger(ChargingPileFallbackFactory.class);
    @Override
    public ChargingPileClient create(Throwable throwable) {
        log.error("充电桩调用失败:{}", throwable.getMessage());
        return new ChargingPileClient() {
            @Override
            public R<List<TChargingPile>> getChargingPileBySiteId(Integer siteId) {
                return R.fail("通过站点id获取充电桩列表失败:"+throwable.getMessage());
            }
            @Override
            public R<List<TChargingPile>> getChargingPileBySiteIds(List<Integer> siteIds) {
                return R.fail("获取数据失败:" + throwable.getMessage());
            }
            @Override
            public R<BigDecimal> getServiceMoney(String param) {
                return R.fail("根据会员折扣、预付金额 计算服务费失败:"+throwable.getMessage());
            }
            @Override
            public R<SiteInfoVO> getSiteInfoByNumber(String number) {
                return R.fail("通过桩编号获取电站信息失败:"+throwable.getMessage());
            }
            @Override
            public R<SiteInfoVO> getSiteInfoByNumber1(String number) {
                return R.fail("通过桩编号获取电站信息失败:"+throwable.getMessage());
            }
            @Override
            public R<TChargingPile> getChargingPileById(Integer id) {
                return R.fail(throwable.getMessage());
            }
            @Override
            public void updateChargingPileStatus(UpdateChargingPileStatusVo vo) {
                log.error("修改充电桩状态失败:" + throwable.getMessage());
            }
        };
    }
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/SiteFallbackFactory.java
New file
@@ -0,0 +1,62 @@
package com.ruoyi.chargingPile.api.factory;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
import com.ruoyi.chargingPile.api.feignClient.SiteClient;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.page.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
/**
 * 充电桩服务降级处理
 *
 * @author ruoyi
 */
@Component
public class SiteFallbackFactory implements FallbackFactory<SiteClient>
{
    private static final Logger log = LoggerFactory.getLogger(SiteFallbackFactory.class);
    @Override
    public SiteClient create(Throwable throwable) {
        log.error("站点调用失败:{}", throwable.getMessage());
        return new SiteClient() {
            @Override
            public R<List<TChargingPile>> getPileListBySiteId(Integer siteId) {
                return R.fail("根据站点id 查询所有充电桩:" + throwable.getMessage());
            }
            @Override
            public R<List<Site>> getSiteByIds(List<Integer> ids) {
                return R.fail("根据id集合获取站点数据调用失败:" + throwable.getMessage());
            }
            @Override
            public R<List<Site>> getSiteAll() {
                return R.fail("获取所有站点调用失败:" + throwable.getMessage());
            }
            @Override
            public R<List<GetSiteListDTO>> getSiteListByUserId(Long userId) {
                return R.fail("获取数据失败" + throwable.getMessage());
            }
            @Override
            public PageInfo<Site> getSiteListPaging(Integer PageNo, Integer PageSize, List<String> ids) {
                return null;
            }
            @Override
            public PageInfo<Site> getSiteListPagingJianGuan(Integer PageNo, Integer PageSize, List<String> ids) {
                return null;
            }
        };
    }
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/AccountingStrategyClient.java
New file
@@ -0,0 +1,25 @@
package com.ruoyi.chargingPile.api.feignClient;
import com.ruoyi.chargingPile.api.factory.AccountingStrategyFallbackFactory;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
 * @author zhibing.pu
 * @Date 2024/9/4 15:51
 */
@FeignClient(contextId = "AccountingStrategyClient", value = ServiceNameConstants.CHARGINGPILE_SERVICE, fallbackFactory = AccountingStrategyFallbackFactory.class)
public interface AccountingStrategyClient {
    /**
     * 根据id查询计费策略
     * @param id
     * @return
     */
    @PostMapping("/t-accounting-strategy/getAccountingStrategyById")
    R<TAccountingStrategy> getAccountingStrategyById(@RequestParam("id") Integer id);
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/AccountingStrategyDetailClient.java
New file
@@ -0,0 +1,62 @@
package com.ruoyi.chargingPile.api.feignClient;
import com.ruoyi.chargingPile.api.dto.CheckChargingStrategyDTO;
import com.ruoyi.chargingPile.api.factory.AccountingStrategyDetailFallbackFactory;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/28 18:33
 */
@FeignClient(contextId = "AccountingStrategyDetailClient", value = ServiceNameConstants.CHARGINGPILE_SERVICE, fallbackFactory = AccountingStrategyDetailFallbackFactory.class)
public interface AccountingStrategyDetailClient {
    /**
     * 通过站点id查询当前时段使用的策略明细
     * @param siteId
     * @return
     */
    @GetMapping("/t-accounting-strategy-detail/getDetailBySiteId")
    R<TAccountingStrategyDetail> getDetailBySiteId(@RequestParam("siteId") Integer siteId);
    /**
     * 通过桩编号查询当前时段使用的策略明细
     * @param code
     * @return
     */
    @GetMapping("/t-accounting-strategy-detail/getDetailByCode")
    R<TAccountingStrategyDetail> getDetailByCode(@RequestParam("code") String code);
    /**
     * 校验充电桩计费模版是否准确
     * @param
     * @return
     */
    @PostMapping("/t-accounting-strategy-detail/checkChargingStrategy")
    R<Boolean> checkChargingStrategy(@RequestBody CheckChargingStrategyDTO dto);
    /**
     * 根据计费策略主表id策略明细
     * @param id
     * @return
     */
    @GetMapping("/t-accounting-strategy-detail/getListByAccountingStrategyId")
    R<List<TAccountingStrategyDetail>> getListByAccountingStrategyId(@RequestParam("id") Integer id);
    /**
     * 通过桩编号查询当前使用的策略明细列表
     * @param code
     * @return
     */
    @GetMapping("/t-accounting-strategy-detail/getDetailListByCode")
    R<List<TAccountingStrategyDetail>> getDetailListByCode(@RequestParam("code") String code);
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/ChargingGunClient.java
New file
@@ -0,0 +1,117 @@
package com.ruoyi.chargingPile.api.feignClient;
import com.ruoyi.chargingPile.api.factory.ChargingGunFallbackFactory;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.vo.GetChargingGunByCode;
import com.ruoyi.chargingPile.api.vo.SiteNameVO;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/15 19:36
 */
@FeignClient(contextId = "ChargingGunClient", value = ServiceNameConstants.CHARGINGPILE_SERVICE, fallbackFactory = ChargingGunFallbackFactory.class)
public interface ChargingGunClient {
    /**
     * 获取所有枪
     * @return
     */
    @PostMapping("/t-charging-gun/getAllGun")
    R<List<TChargingGun>> getAllGun();
    /**
     * 获取所有桩
     * @return
     */
    @PostMapping("/t-charging-gun/getAllPile")
    R<List<TChargingPile>> getAllPile();
    /**
     * 根据id获取充电枪完整名称
     * @param id
     * @return
     */
    @PostMapping("/t-charging-gun/getAllName/{id}")
    R<String> getAllName(@PathVariable("id") Integer id);
    /**
     * 根据id获取充电枪
     * @param id
     * @return
     */
    @PostMapping("/t-charging-gun/getChargingGunById/{id}")
    R<TChargingGun> getChargingGunById(@PathVariable("id") Integer id);
    /**
     * 通过枪id获取站点、桩、枪的名称VO
     * @param id
     * @return
     */
    @PostMapping("/t-charging-gun/getAllInfoById/{id}")
    R<SiteNameVO> getAllInfoById(@PathVariable("id") Integer id);
    /**
     * 根据枪编号获取充电枪
     * @param code
     * @return
     */
    @PostMapping("/t-charging-gun/getChargingGunByCode")
    R<TChargingGun> getChargingGunByCode(@RequestBody GetChargingGunByCode code);
    /**
     * 编辑充电枪
     * @param chargingGun
     * @return
     */
    @PostMapping("/t-charging-gun/updateChargingGunById")
    R<String> updateChargingGunById(@RequestBody TChargingGun chargingGun);
    /**
     * 根据充电桩id获取枪
     * @param chargingPileId
     * @return
     */
    @PostMapping("/t-charging-gun/getChargingGunByChargingPileId")
    R<List<TChargingGun>> getChargingGunByChargingPileId(@RequestParam("chargingPileId") Integer chargingPileId);
    /**
     * 根据充电桩ids获取枪
     * @param chargingPileIds
     * @return
     */
    @PostMapping("/t-charging-gun/getChargingGunByChargingPileIds")
    R<List<TChargingGun>> getChargingGunByChargingPileIds(@RequestParam("chargingPileIds") List<Integer> chargingPileIds);
    /**
     * 接口状态变化后推送给第三方
     * @param id
     * @param status
     * @return
     */
    @PostMapping("/t-charging-gun/pushChargingGunStatus")
    R pushChargingGunStatus(@RequestParam("id") Integer id, @RequestParam("status") Integer status);
    /**
     * 根据枪唯一码查询信息
     * @return
     */
    @PostMapping("/t-charging-gun/getChargingGunByFullNumber")
    R<TChargingGun> getChargingGunByFullNumber(@RequestParam("fullNumber") String fullNumber);
    /**
     * 大屏 根据站点ids和充电模式集合查询充电枪集合
     */
    @GetMapping("/t-charging-gun/getGunIdsBySiteIdsAndChargeModels")
    R<List<Integer>> getGunIdsBySiteIdsAndChargeModels(@RequestParam("siteIds") List<Integer> siteIds ,@RequestParam("chargeModels") List<Integer> chargeModels);
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/ChargingPileClient.java
New file
@@ -0,0 +1,57 @@
package com.ruoyi.chargingPile.api.feignClient;
import com.ruoyi.chargingPile.api.factory.ChargingPileFallbackFactory;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.vo.SiteInfoVO;
import com.ruoyi.chargingPile.api.vo.UpdateChargingPileStatusVo;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
/**
 * 充电桩服务
 * @author ruoyi
 */
@FeignClient(contextId = "ChargingPileClient", value = ServiceNameConstants.CHARGINGPILE_SERVICE, fallbackFactory = ChargingPileFallbackFactory.class)
public interface ChargingPileClient {
    /**
     * 管理后台-通过站点id获取充电桩列表 不分页
     */
    @ApiOperation(value = "管理后台-通过站点id获取充电桩列表 不分页")
    @PostMapping(value = "/t-charging-pile/getChargingPileBySiteId")
    R<List<TChargingPile>> getChargingPileBySiteId(@RequestParam("siteId") Integer siteId);
    @ApiOperation(value = "获取站点列表")
    @PostMapping(value = "/t-charging-pile/getChargingPileBySiteIds")
    R<List<TChargingPile>> getChargingPileBySiteIds(@RequestParam("siteIds") List<Integer> siteIds);
    /**
     * 小程序远程调用 根据会员折扣、预付金额 计算服务费
     * @return
     */
    @PostMapping(value = "/t-accounting-strategy/getServiceMoney")
    R<BigDecimal> getServiceMoney(@RequestParam("param") String param);
    @GetMapping("/site/getSiteInfoByNumber")
    R<SiteInfoVO> getSiteInfoByNumber(@RequestParam("number") String number);
    @PostMapping("/site/getSiteInfoByNumber1")
    R<SiteInfoVO> getSiteInfoByNumber1(@RequestParam("number") String number);
    @PostMapping("/t-charging-pile/getChargingPileById/{id}")
    R<TChargingPile> getChargingPileById(@PathVariable("id") Integer id);
    /**
     * 修改充电桩状态
     */
    @PostMapping("/t-charging-pile/updateChargingPileStatus")
    void updateChargingPileStatus(@RequestBody UpdateChargingPileStatusVo vo);
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/SiteClient.java
New file
@@ -0,0 +1,64 @@
package com.ruoyi.chargingPile.api.feignClient;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
import com.ruoyi.chargingPile.api.factory.SiteFallbackFactory;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.page.PageInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/10 14:38
 */
@FeignClient(contextId = "SiteClient", value = ServiceNameConstants.CHARGINGPILE_SERVICE, fallbackFactory = SiteFallbackFactory.class)
public interface SiteClient {
    @GetMapping("/site/getPileListBySiteId/{siteId}")
    public R<List<TChargingPile>> getPileListBySiteId(@PathVariable("siteId")Integer siteId);
    /**
     * 根据id集合获取数据
     * @param ids
     * @return
     */
    @PostMapping("/site/getSiteByIds")
    R<List<Site>> getSiteByIds(@RequestBody List<Integer> ids);
    /**
     * 获取所有站点
     * @return
     */
    @PostMapping("/site/getSiteAll")
    R<List<Site>> getSiteAll();
    @GetMapping("/site/getSiteList/byUserId")
    R<List<GetSiteListDTO>> getSiteListByUserId(@RequestParam("userId") Long userId);
    /**
     * 分页查询站电数据
     * @param PageNo
     * @param PageSize
     * @return
     */
    @PostMapping("/site/getSiteListPaging")
    PageInfo<Site> getSiteListPaging(@RequestParam("PageNo") Integer PageNo,
                                     @RequestParam("PageSize") Integer PageSize,
                                     @RequestParam("ids") List<String> ids);
    /**
     * 分页查询站电数据
     * @param PageNo
     * @param PageSize
     * @return
     */
    @PostMapping("/site/getSiteListPagingJianGuan")
    PageInfo<Site> getSiteListPagingJianGuan(@RequestParam("PageNo") Integer PageNo,
                                     @RequestParam("PageSize") Integer PageSize,
                                     @RequestParam("ids") List<String> ids);
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/Site.java
New file
@@ -0,0 +1,233 @@
package com.ruoyi.chargingPile.api.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 19:31
 */
@Data
@TableName("t_site")
public class Site extends BasePojo {
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    @ApiModelProperty(value = "站点id")
    private Integer id;
    /**
     * 站点编号
     */
    @TableField("user_id")
    @ApiModelProperty(value = "用户id")
    private Long userId;
    /**
     * 站点编号
     */
    @TableField("code")
    @ApiModelProperty(value = "站点编号", required = true)
    private String code;
    /**
     * 站点名称
     */
    @TableField("name")
    @ApiModelProperty(value = "站点名称", required = true)
    private String name;
    /**
     * 站点类型(0=其他,1=公共,2=个人,3=公交(专业),4=环卫(专用),5=物流(专用),6=出租车(专用))
     */
    @TableField("site_type")
    @ApiModelProperty(value = "站点类型(0=其他,1=公共,2=个人,3=公交(专业),4=环卫(专用),5=物流(专用),6=出租车(专用),7=分时租赁(专用),8=小区共享(专用),9=单位(专用),10=私人共享桩(专用))", required = true)
    private Integer siteType;
    /**
     * 经营类型(1=直营,2=非直营)
     */
    @TableField("business_category")
    @ApiModelProperty(value = "经营类型(1=直营,2=非直营)", required = true)
    private Integer businessCategory;
    /**
     * 站点状态(1=正常使用,2=维修中,3=关闭下线)
     */
    @TableField("status")
    @ApiModelProperty(value = "站点状态(1=正常使用,2=维修中,3=关闭下线)", required = true)
    private Integer status;
    /**
     * 建设场所(0=其他,1=居民区,2=公共机构,3=企事业单位,4=写字楼,5=工业园区,6=交通枢纽,7=大型文体设施,8=城市绿地,9=大型建筑配建停车场,10=路边停车位,11=城际高速服务区)
     */
    @TableField("construction_site")
    @ApiModelProperty(value = "建设场所(0=其他,1=居民区,2=公共机构,3=企事业单位,4=写字楼,5=工业园区,6=交通枢纽,7=大型文体设施,8=城市绿地,9=大型建筑配建停车场,10=路边停车位,11=城际高速服务区),12=风景区,13=公交场站,14=加油加气站,15=出租车", required = true)
    private Integer constructionSite;
    /**
     * 站点环境图
     */
    @TableField("img_url")
    @ApiModelProperty(value = "站点环境图", required = true)
    private String imgUrl;
    /**
     * 省名称
     */
    @TableField("province")
    @ApiModelProperty(value = "省名称", required = true)
    private String province;
    /**
     * 省区划代码
     */
    @TableField("province_code")
    @ApiModelProperty(value = "省区划代码", required = true)
    private String provinceCode;
    /**
     * 市名称
     */
    @TableField("city")
    @ApiModelProperty(value = "市名称", required = true)
    private String city;
    /**
     * 市区划代码
     */
    @TableField("city_code")
    @ApiModelProperty(value = "市区划代码", required = true)
    private String cityCode;
    /**
     * 区县名称
     */
    @TableField("districts")
    @ApiModelProperty(value = "区县名称", required = true)
    private String districts;
    /**
     * 区县区划代码
     */
    @TableField("districts_code")
    @ApiModelProperty(value = "区县区划代码", required = true)
    private String districtsCode;
    /**
     * 经度
     */
    @TableField("lon")
    @ApiModelProperty(value = "经度", required = true)
    private String lon;
    /**
     * 纬度
     */
    @TableField("lat")
    @ApiModelProperty(value = "纬度", required = true)
    private String lat;
    /**
     * 详细地址
     */
    @TableField("address")
    @ApiModelProperty(value = "详细地址", required = true)
    private String address;
    /**
     * 国家代码
     */
    @TableField("country_code")
    @ApiModelProperty(value = "国家代码")
    private String countryCode;
    /**
     * 站点电话
     */
    @TableField("phone")
    @ApiModelProperty(value = "站点电话", required = true)
    private String phone;
    /**
     * 服务电话
     */
    @TableField("service_phone")
    @ApiModelProperty(value = "服务电话", required = true)
    private String servicePhone;
    /**
     * 站点引导
     */
    @TableField("guide")
    @ApiModelProperty(value = "站点引导")
    private String guide;
    /**
     * 开始服务时间
     */
    @TableField("start_service_time")
    @ApiModelProperty(value = "2.0修改字段-运营时间,{\"1\":[\"09:00-17:30\",\"19:30-22:00\"],\"2\":[\"09:00-17:30\",\"19:30-22:00\"],\"3\":[\"09:00-17:30,\"19:30-2:00\"],\"4\":[\"09:00-17:30\"],5\":[\"09:00-17:30\"],\"6\":[\"09:00-17:30\"],\"7\":[\"09:00-17:30\"]}")
    private String startServiceTime;
    /**
     * 结束服务时间
     */
    @TableField("end_service_time")
    @ApiModelProperty(value = "结束服务时间")
    private String endServiceTime;
    /**
     * 站内提供服务
     */
    @TableField("service_description")
    @ApiModelProperty(value = "站内提供服务")
    private String serviceDescription;
    /**
     * 车型描述
     */
    @TableField("vehicle_description")
    @ApiModelProperty(value = "车型描述")
    private String vehicleDescription;
    /**
     * 车位数
     */
    @TableField("parking_space")
    @ApiModelProperty(value = "车位数", required = true)
    private Integer parkingSpace;
    /**
     * 充电费率描述
     */
    @TableField("rate_description")
    @ApiModelProperty(value = "充电费率描述")
    private String rateDescription;
    /**
     * 超时占位费说明
     */
    @TableField("space_charge_explain")
    @ApiModelProperty(value = "超时占位费说明")
    private String spaceChargeExplain;
    /**
     * 计费策略id
     */
    @TableField("accounting_strategy_id")
    @ApiModelProperty(value = "计费策略id")
    private Integer accountingStrategyId;
    /**
     * 建站时间
     */
    @TableField("establishment_time")
    @ApiModelProperty(value = "建站时间", notes = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime establishmentTime;
    /**
     * 排序
     */
    @TableField("sort")
    @ApiModelProperty(value = "排序", required = true)
    private Integer sort;
    /**
     * 备注
     */
    @TableField("remark")
    @ApiModelProperty(value = "备注")
    private String remark;
    /**
     * 年服务费
     */
    @TableField("annual_service_fee")
    @ApiModelProperty(value = "年服务费")
    private BigDecimal annualServiceFee;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TAccountingStrategy.java
New file
@@ -0,0 +1,92 @@
package com.ruoyi.chargingPile.api.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
 * 计费策略
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_accounting_strategy")
@ApiModel(value="TAccountingStrategy对象", description="计费策略")
public class TAccountingStrategy extends BasePojo {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "站点id")
    @TableField("site_id")
    private Integer siteId;
    @ApiModelProperty(value = "申请人id")
    @TableField("user_id")
    private Long userId;
    @ApiModelProperty(value = "策略名称")
    @TableField("name")
    private String name;
    @ApiModelProperty(value = "策略说明")
    @TableField("description")
    private String description;
    @ApiModelProperty(value = "会员折扣")
    @TableField("discount")
    private BigDecimal discount;
    @ApiModelProperty(value = "一级审核用户id")
    @TableField("first_user_id")
    private Long firstUserId;
    @ApiModelProperty(value = "二级审核用户id")
    @TableField("two_user_id")
    private Long twoUserId;
    @ApiModelProperty(value = "一级审核备注")
    @TableField("first_remark")
    private String firstRemark;
    @ApiModelProperty(value = "二级审核备注")
    @TableField("two_remark")
    private String twoRemark;
    @ApiModelProperty(value = "审核状态(1=待审核一级,2=待审核二级,3=审核通过,4=驳回)")
    @TableField("audit_status")
    private Integer auditStatus;
    @ApiModelProperty(value = "一级审核时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField("first_audit_time")
    private LocalDateTime firstAuditTime;
    @ApiModelProperty(value = "二级审核时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField("two_audit_time")
    private LocalDateTime twoAuditTime;
    @ApiModelProperty(value = "父级id  上一次已审核通过的id  为空则代表是新增,或者本次数据状态审核中或已拒绝")
    @TableField("parent_id")
    private Integer parentId;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TAccountingStrategyDetail.java
New file
@@ -0,0 +1,65 @@
package com.ruoyi.chargingPile.api.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
/**
 * <p>
 * 计费策略明细
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_accounting_strategy_detail")
@ApiModel(value="TAccountingStrategyDetail对象", description="计费策略明细")
public class TAccountingStrategyDetail extends BasePojo {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "策略id")
    @TableField("accounting_strategy_id")
    private Integer accountingStrategyId;
    @ApiModelProperty(value = "阶段(1=尖阶段,2=峰阶段,3=平阶段,4=谷阶段)")
    @TableField("type")
    private Integer type;
    @ApiModelProperty(value = "开始时间")
    @TableField("start_time")
    private String startTime;
    @ApiModelProperty(value = "结束时间")
    @TableField("end_time")
    private String endTime;
    @ApiModelProperty(value = "电价")
    @TableField("electrovalence")
    private BigDecimal electrovalence;
    @ApiModelProperty(value = "服务费")
    @TableField("service_charge")
    private BigDecimal serviceCharge;
    @ApiModelProperty(value = "原价服务费")
    @TableField("cost_service_charge")
    private BigDecimal costServiceCharge;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TChargingGun.java
New file
@@ -0,0 +1,151 @@
package com.ruoyi.chargingPile.api.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.web.domain.BaseModel;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
 * 充电枪
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_charging_gun")
@ApiModel(value="TChargingGun对象", description="充电枪")
public class TChargingGun extends BasePojo {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "充电枪编号", required = true)
    @TableField("code")
    private String code;
    @ApiModelProperty(value = "站点id", required = true)
    @TableField("site_id")
    private Integer siteId;
    @ApiModelProperty(value = "合作商id", required = true)
    @TableField("partner_id")
    private Integer partnerId;
    @ApiModelProperty(value = "充电桩id", required = true)
    @TableField("charging_pile_id")
    private Integer chargingPileId;
    @ApiModelProperty(value = "充电枪名称", required = true)
    @TableField("name")
    private String name;
    @ApiModelProperty(value = "充电枪类型(0=其他,1=家用插座(模式2),2=交流接口插座(模式3,连接方式B),3=交流接口插头(带枪线,模式3,连接方式C)4=直流接口枪头(带枪线,模式4)5=无线充电座)", required = true)
    @TableField("type")
    private Integer type;
    @ApiModelProperty(value = "充电枪状态(1=离线,2=空闲,3=占用(未充电),4=占用(充电中),5=占用(已充满),6=占用(预约锁定),7=故障)", required = true)
    @TableField("status")
    private Integer status;
    @ApiModelProperty(value = "充电模式(1=超级快充,2=快充,3=慢充)", required = true)
    @TableField("charge_mode")
    private Integer chargeMode;
    @ApiModelProperty(value = "计费策略id")
    @TableField("accounting_strategy_id")
    private Integer accountingStrategyId;
    @ApiModelProperty(value = "额定电压上限", required = true)
    @TableField("upper_rated_voltage")
    private BigDecimal upperRatedVoltage;
    @ApiModelProperty(value = "额定电压下限", required = true)
    @TableField("lower_limit_of_rated_voltage")
    private BigDecimal lowerLimitOfRatedVoltage;
    @ApiModelProperty(value = "额定电流", required = true)
    @TableField("rated_current")
    private BigDecimal ratedCurrent;
    @ApiModelProperty(value = "额定功率", required = true)
    @TableField("rated_power")
    private BigDecimal ratedPower;
    @ApiModelProperty(value = "实时充电功率", required = true)
    @TableField("charging_power")
    private BigDecimal chargingPower;
    @ApiModelProperty(value = "车位号")
    @TableField("parking_number")
    private String parkingNumber;
    @ApiModelProperty(value = "车位状态(0=未知,1=空闲,2=占用)")
    @TableField("parking_status")
    private Integer parkingStatus;
    @ApiModelProperty(value = "地锁状态|(0=未知,1=已解锁,2=已上锁)")
    @TableField("parking_lock_state")
    private Integer parkingLockState;
    @ApiModelProperty(value = "国家标准 1:2011\n" +
            "2:2015\n" +
            "3:兼容2011和2015", required = true)
    @TableField("national_standard")
    private String nationalStandard;
    @ApiModelProperty(value = "说明")
    @TableField("remark")
    private String remark;
    @ApiModelProperty(value = "已充电百分比")
    @TableField(exist = false)
    private Integer soc;
    @ApiModelProperty(value = "完整编号(桩号+抢号)")
    @TableField("fullNumber")
    private String fullNumber;
    @ApiModelProperty(value = "2.0修改字段 设备接口分类 1:车辆充电设备接口\n" +
            "2:换电站内的电池箱充电设备\n" +
            "接口" , required = true)
    @TableField("equipment_classification")
    private Integer equipmentClassification;
    @ApiModelProperty(value = "2.0修改字段-恒功率电压上限", required = false)
    @TableField("constant_voltage_upper_limits")
    private BigDecimal constantVoltageUpperLimits;
    @ApiModelProperty(value = "2.0修改字段-恒功率电压下限", required = false)
    @TableField("constant_voltage_lower_limits")
    private BigDecimal constantVoltageLowerLimits;
    @ApiModelProperty(value = "2.0修改字段-恒功率电流上限", required = false)
    @TableField("constant_current_upper_limits")
    private BigDecimal constantCurrentUpperLimits;
    @ApiModelProperty(value = "2.0修改字段-恒功率电流下限", required = false)
    @TableField("constant_current_lower_limits")
    private BigDecimal constantCurrentLowerLimits;
    @ApiModelProperty(value = "2.0修改字段-辅助电源 1:12V2:24V3:兼容12V和24V",required = true)
    @TableField("aux_power")
    private Integer auxPower;
    @ApiModelProperty(value = "2.0修改字段-运营状态0:未知1:建设中5:关闭下线6:维护中50:正常使用",required = true)
    @TableField("opreate_status")
    private Integer opreateStatus;
    @ApiModelProperty(value = "2.0修改字段-运营时间描述")
    @TableField("opreate_hours")
    private String opreateHours;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TChargingPile.java
New file
@@ -0,0 +1,115 @@
package com.ruoyi.chargingPile.api.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
 * <p>
 * 充电桩
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_charging_pile")
@ApiModel(value="TChargingPile对象", description="充电桩")
public class TChargingPile extends BasePojo {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "设备编号", required = true)
    @TableField("code")
    private String code;
    @ApiModelProperty(value = "充电设备名称", required = true)
    @TableField("name")
    private String name;
    @ApiModelProperty(value = "桩号", required = true)
    @TableField("number")
    private Integer number;
    @ApiModelProperty(value = "设备类型(0=其他,1=直流设备,2=交流设备,3=交直流一体设备,4=无线设备 5=有序 6=V2G)", required = true)
    @TableField("type")
    private Integer type;
    @ApiModelProperty(value = "站点id", required = true)
    @TableField("site_id")
    private Integer siteId;
    @ApiModelProperty(value = "站点名称")
    @TableField(exist = false)
    private String siteName;
    @ApiModelProperty(value = "合作商id", required = true)
    @TableField("partner_id")
    private Integer partnerId;
    @ApiModelProperty(value = "合作商名称")
    @TableField(exist = false)
    private String partnerName;
    @ApiModelProperty(value = "生产商机构代码")
    @TableField("manufacturer_code")
    private String manufacturerCode;
    @ApiModelProperty(value = "生产商名称")
    @TableField("manufacturer")
    private String manufacturer;
    @ApiModelProperty(value = "设备型号")
    @TableField("equipment_type")
    private String equipmentType;
    @ApiModelProperty(value = "生产日期")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    @TableField("production_date")
    private LocalDate productionDate;
    @ApiModelProperty(value = "额定功率", required = true)
    @TableField("rated_power")
    private BigDecimal ratedPower;
    @ApiModelProperty(value = "设备充电站编号")
    @TableField("charging_station_number")
    private String chargingStationNumber;
    @ApiModelProperty(value = "设备状态(1=工作中,2=离线,3=故障)")
    @TableField("status")
    private Integer status;
    @ApiModelProperty(value = "iotd设备id")
    @TableField("iotd_device_id")
    private String iotdDeviceId;
    @ApiModelProperty(value = "设备分类 1:车辆充电设备2:换电站内的电池箱充电设备")
    @TableField("equipment_classification")
    private Integer equipmentClassification;
    @ApiModelProperty(value = "设备唯一编码")
    @TableField("equipment_unique_number")
    private String equipmentUniqueNumber;
    @ApiModelProperty(value = "充电设备经度")
    @TableField("equipment_lng")
    private String equipmentLng;
    @ApiModelProperty(value = "充电设备纬度")
    @TableField("equipment_lat")
    private String equipmentLat;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/BatchSetAccountingStrategy.java
New file
@@ -0,0 +1,20 @@
package com.ruoyi.chargingPile.api.query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/8 16:36
 */
@Data
@ApiModel
public class BatchSetAccountingStrategy {
    @ApiModelProperty(value = "充电桩id", required = true)
    private List<Integer> id;
    @ApiModelProperty(value = "计费策略id", required = true)
    private Integer accountingStrategyId;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/GetPartnerList.java
New file
@@ -0,0 +1,19 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 13:54
 */
@Data
@ApiModel
public class GetPartnerList extends BasePage {
    @ApiModelProperty(value = "合作商名称")
    private String name;
    @ApiModelProperty(value = "角色id")
    private Integer roleId;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/GetSiteList.java
New file
@@ -0,0 +1,32 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Value;
/**
 * @author zhibing.pu
 * @Date 2024/8/8 9:24
 */
@Data
@ApiModel
public class GetSiteList extends BasePage {
    @ApiModelProperty(value = "站点名称")
    private String name;
    @ApiModelProperty(value = "合作商名称")
    private String partnerName;
    @ApiModelProperty(value = "站点类型(0=其他,1=公共,2=个人,3=公交(专业),4=环卫(专用),5=物流(专用),6=出租车(专用))")
    private Integer siteType;
    @ApiModelProperty(value = "经营类型(1=直营,2=非直营)")
    private Integer businessCategory;
    @ApiModelProperty(value = "站点状态(1=正常使用,2=维修中,3=关闭下线)")
    private Integer status;
    @ApiModelProperty(value = "站点省代码")
    private String provinceCode;
    @ApiModelProperty(value = "站点市代码")
    private String cityCode;
    @ApiModelProperty(value = "站点区代码")
    private String districtsCode;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/PageChargingPileList.java
New file
@@ -0,0 +1,22 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.domain.BasePojo;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/8 15:04
 */
@Data
@ApiModel
public class PageChargingPileList extends BasePage {
    @ApiModelProperty(value = "站点id")
    private Integer siteId;
    @ApiModelProperty("充电设备名称")
    private String name;
    @ApiModelProperty("设备类型(0=其他,1=直流设备,2=交流设备,3=交直流一体设备,4=无线设备)")
    private Integer type;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/ParkingRecordQuery.java
New file
@@ -0,0 +1,28 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.query.TimeRangePageQuery;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "停车缴费订单Query")
public class ParkingRecordQuery extends TimeRangePageQuery {
    @ApiModelProperty(value = "站点id")
    private Integer siteId;
    @ApiModelProperty(value = "订单编号")
    private String code;
    @ApiModelProperty(value = "车牌号")
    private String licensePlate;
    @ApiModelProperty(value = "停车场id集合 前端忽略")
    private List<Integer> lotIds;
    @ApiModelProperty(value = "站点id集合 前端忽略")
    private List<Integer> siteIds;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/SetPermissionConfiguration.java
New file
@@ -0,0 +1,24 @@
package com.ruoyi.chargingPile.api.query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/9 11:13
 */
@Data
@ApiModel
public class SetPermissionConfiguration {
    @ApiModelProperty(value = "备注")
    private String permissionRemarks;
    @ApiModelProperty(value = "权限菜单id数组", required = true)
    private List<Integer> menuId;
    @ApiModelProperty(value = "站点id", required = true)
    private Integer siteId;
    @ApiModelProperty(value = "合作商id", required = true)
    private Integer partnerId;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/SiteDetailQuery.java
New file
@@ -0,0 +1,27 @@
package com.ruoyi.chargingPile.api.query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@Data
@ApiModel(value = "SiteDetailQuery对象",description = "站点详情查询条件")
public class SiteDetailQuery implements Serializable {
    @ApiModelProperty(value = "站点id")
    @NotNull(message = "站点id不能为空")
    private Integer siteId;
    @ApiModelProperty(value = "经度")
    @NotBlank(message = "地址经度不能为空")
    private String lon;
    @ApiModelProperty(value = "纬度")
    @NotBlank(message = "地址纬度不能为空")
    private String lat;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/SiteQuery.java
New file
@@ -0,0 +1,32 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "SiteQuery对象",description = "站点查询条件")
public class SiteQuery extends BasePage {
    @ApiModelProperty(value = "站点名称")
    private String name;
    @ApiModelProperty(value = "排序方式 1=离我最近 2=价格较低 3=空闲较多")
    @NotNull(message = "排序方式不能为空")
    private Integer sortType;
    @ApiModelProperty(value = "经度")
    @NotNull(message = "地址经度不能为空")
    private String lon;
    @ApiModelProperty(value = "纬度")
    @NotNull(message = "地址纬度不能为空")
    private String lat;
    @ApiModelProperty(value = "城市code")
    private String cityCode;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TAccountingStrategyQuery.java
New file
@@ -0,0 +1,18 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value="TAccountingStrategyQuery对象", description="计费策略")
public class TAccountingStrategyQuery extends BasePage {
    @ApiModelProperty(value = "计费策略名称")
    private String name;
    @ApiModelProperty(value = "1=待审核一级,2=待审核二级,3=审核通过,4=驳回")
    private Integer auditStatus;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TChargingGunQuery.java
New file
@@ -0,0 +1,32 @@
package com.ruoyi.chargingPile.api.query;
import com.baomidou.mybatisplus.annotation.TableField;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value="TChargingGunQuery对象", description="充电枪")
public class TChargingGunQuery extends BasePage {
    @ApiModelProperty(value = "站点id")
    private Integer siteId;
    @ApiModelProperty(value = "充电桩id")
    private Integer chargingPileId;
    @ApiModelProperty(value = "充电枪名称")
    @TableField("name")
    private String name;
    @ApiModelProperty(value = "充电枪类型(0=其他,1=家用插座(模式2),2=交流接口插座(模式3,连接方式B),3=交流接口插头(带枪线,模式3,连接方式C)4=直流接口枪头(带枪线,模式4)5=无线充电座)")
    private Integer type;
    @ApiModelProperty(value = "充电枪状态(1=离线,2=空闲,3=占用(未充电),4=占用(充电中),5=占用(已充满),6=占用(预约锁定),7=故障)")
    private Integer status;
    @ApiModelProperty(value = "充电模式(1=超级快充,2=快充,3=慢充)")
    private Integer chargeMode;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TMonitoringEquipmentQuery.java
New file
@@ -0,0 +1,15 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "监控查询Query")
public class TMonitoringEquipmentQuery extends BasePage {
    @ApiModelProperty(value = "停车场id")
    private Integer parkingLotId;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TParkingLotQuery.java
New file
@@ -0,0 +1,21 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "停车场查询Query")
public class TParkingLotQuery extends BasePage {
    @ApiModelProperty(value = "停车场名称")
    private String name;
    @ApiModelProperty(value = "第三方停车场编号")
    private String code;
    @ApiModelProperty(value = "站点id")
    private Integer siteId;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/query/TVehicleRampQuery.java
New file
@@ -0,0 +1,13 @@
package com.ruoyi.chargingPile.api.query;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "车道查询Query")
public class TVehicleRampQuery extends BasePage {
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/ChargingGunCountVO.java
New file
@@ -0,0 +1,23 @@
package com.ruoyi.chargingPile.api.vo;
import com.ruoyi.chargingPile.api.model.Site;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ChargingGunCountVO对象",description = "充电枪数量VO")
public class ChargingGunCountVO extends Site {
    @ApiModelProperty(value = "充电枪空闲数量")
    private Integer freeCount;
    @ApiModelProperty(value = "充电枪总数数量")
    private Integer totalCount;
    public ChargingGunCountVO(Integer freeCount, Integer totalCount) {
        this.freeCount = freeCount;
        this.totalCount = totalCount;
    }
    public ChargingGunCountVO() {
    }
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/GetChargingGunByCode.java
New file
@@ -0,0 +1,13 @@
package com.ruoyi.chargingPile.api.vo;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/10/8 16:58
 */
@Data
public class GetChargingGunByCode {
    private String charging_pile_code; // 桩编码
    private String charging_gun_code; // 抢号
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/GetParkingRecord.java
New file
@@ -0,0 +1,19 @@
package com.ruoyi.chargingPile.api.vo;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/9/5 14:16
 */
@Data
public class GetParkingRecord {
    /**
     * 车牌
     */
    private String licensePlate;
    /**
     * 状态(1=已进场,2=已出场,3=已缴费出场)
     */
    private Integer status;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/GunStatusStatisticsVO.java
New file
@@ -0,0 +1,21 @@
package com.ruoyi.chargingPile.api.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@Data
@ApiModel(value = "设备状态统计VO")
public class GunStatusStatisticsVO  {
    @ApiModelProperty(value = "充电桩类型统计 key:充电模式(1=超级快充,2=快充,3=慢充)")
    private List<Map<String,Object>> modeStatistics;
    @ApiModelProperty(value = "状态统计 key:充电模式(1=离线,2=故障,3=充电中)")
    private List<Map<String,Integer>> statusStatistics;
    @ApiModelProperty(value = "状态统计根据类型分组")
    private List<StatusModeStatisticsVO> statusModeStatistics;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteDetailVO.java
New file
@@ -0,0 +1,19 @@
package com.ruoyi.chargingPile.api.vo;
import com.ruoyi.chargingPile.api.model.Site;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "SiteDetailVO对象",description = "站点详情VO")
public class SiteDetailVO extends Site {
    @ApiModelProperty(value = "合作商名称")
    private String partnerName;
    @ApiModelProperty(value = "绑定车牌提示文案")
    private String bindCarTips;
    @ApiModelProperty(value = "距离")
    private double distance;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteInfoVO.java
New file
@@ -0,0 +1,46 @@
package com.ruoyi.chargingPile.api.vo;
import com.ruoyi.chargingPile.api.model.Site;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "SiteVO对象", description = "小程序扫一扫-详情页面")
public class SiteInfoVO  {
    @ApiModelProperty(value = "电站名称")
    private String name;
    @ApiModelProperty(value = "桩id")
    private Integer chargingPileId;
    @ApiModelProperty(value = "站点id")
    private Integer siteId;
    @ApiModelProperty(value = "桩编号")
    private String number;
    @ApiModelProperty(value = "充电枪id")
    private Integer chargingGunId;
    @ApiModelProperty(value = "普通电价")
    private BigDecimal electrovalence;
    @ApiModelProperty(value = "会员电价")
    private BigDecimal vipElectrovalence;
    @ApiModelProperty(value = "开通会员预计可省")
    private BigDecimal money;
    @ApiModelProperty(value = "额外赠送优惠券X张")
    private Integer couponCount = 0;
    @ApiModelProperty(value = "超时占位费说明")
    private String spaceChargeExplain;
    @ApiModelProperty(value = "添加车辆最高可得积分 车辆信息为空 展示提示语")
    private Integer integral;
    @ApiModelProperty(value = "充电模式(1=超级快充,2=快充,3=慢充")
    private Integer chargeMode;
    @ApiModelProperty(value = "上次选择车辆logo")
    private String carLogo;
    @ApiModelProperty(value = "上次选择车辆车牌号")
    private String licensePlate;
    @ApiModelProperty(value = "上次选择车辆品牌")
    private String vehicleBrand;
    @ApiModelProperty(value = "上次选择车辆id")
    private String id;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteNameVO.java
New file
@@ -0,0 +1,24 @@
package com.ruoyi.chargingPile.api.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "获取站点、桩、枪的名称VO")
public class SiteNameVO implements Serializable {
    @ApiModelProperty(value = "站点名称")
    private String siteName;
    @ApiModelProperty(value = "桩名称")
    private String pileName;
    @ApiModelProperty(value = "桩号")
    private Integer pileNumber;
    @ApiModelProperty(value = "枪名称")
    private String gunName;
    @ApiModelProperty(value = "枪号")
    private String gunNumber;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteVO.java
New file
@@ -0,0 +1,37 @@
package com.ruoyi.chargingPile.api.vo;
import com.ruoyi.chargingPile.api.model.Site;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "SiteVO对象", description = "站点信息")
public class SiteVO extends Site {
    @ApiModelProperty(value = "快充数量")
    private Integer fastCount;
    @ApiModelProperty(value = "超充数量")
    private Integer superCount;
    @ApiModelProperty(value = "慢充数量")
    private Integer slowCount;
    @ApiModelProperty(value = "快充空闲数量")
    private Integer superFreeCount;
    @ApiModelProperty(value = "超充空闲数量")
    private Integer fastFreeCount;
    @ApiModelProperty(value = "慢充空闲数量")
    private Integer slowFreeCount;
    @ApiModelProperty(value = "原始电价")
    private BigDecimal electrovalenceOriginal;
    @ApiModelProperty(value = "服务费")
    private BigDecimal serviceCharge;
    @ApiModelProperty(value = "普通电价")
    private BigDecimal electrovalence;
    @ApiModelProperty(value = "会员电价")
    private BigDecimal vipElectrovalence;
    @ApiModelProperty(value = "距离 单位米")
    private BigDecimal distance;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/StatusModeStatisticsVO.java
New file
@@ -0,0 +1,33 @@
package com.ruoyi.chargingPile.api.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "状态统计根据类型分组VO")
public class StatusModeStatisticsVO implements Serializable {
    @ApiModelProperty(value = "充电模式(1=超级快充,2=快充,3=慢充)")
    private Integer chargeMode;
    @ApiModelProperty(value = "空闲")
    private Integer freeCount;
    @ApiModelProperty(value = "充满")
    private Integer filledCount;
    @ApiModelProperty(value = "插枪")
    private Integer insertCount;
    @ApiModelProperty(value = "充电中")
    private Integer chargingCount;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/StrategyPriceVO.java
New file
@@ -0,0 +1,29 @@
package com.ruoyi.chargingPile.api.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@ApiModel(value = "StrategyPriceVO对象",description = "价格说明金额返回,会员开通金额说明")
public class StrategyPriceVO implements Serializable {
    @ApiModelProperty(value = "优惠金额")
    private BigDecimal discountAmount;
    @ApiModelProperty(value = "最高优惠金额")
    private BigDecimal maxDiscountAmount;
    @ApiModelProperty(value = "会员起步价")
    private BigDecimal vipStartPrice;
    @ApiModelProperty(value = "服务费折扣")
    private BigDecimal serviceFeeDiscount;
    @ApiModelProperty(value = "模板折扣几折")
    private BigDecimal discount;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TAccountingStrategyDetailVO.java
New file
@@ -0,0 +1,20 @@
package com.ruoyi.chargingPile.api.vo;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "TAccountingStrategyDetailVO",description = "计费策略明细")
public class TAccountingStrategyDetailVO extends TAccountingStrategyDetail {
    @ApiModelProperty(value = "总价")
    private BigDecimal totalPrice;
    @ApiModelProperty(value = "会员折扣")
    private BigDecimal discount;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TAccountingStrategyVO.java
New file
@@ -0,0 +1,28 @@
package com.ruoyi.chargingPile.api.vo;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "计费策略VO")
public class TAccountingStrategyVO extends TAccountingStrategy {
    @ApiModelProperty(value = "计费策略明细集合")
    private List<TAccountingStrategyDetail> accountingStrategyDetailList;
    @ApiModelProperty(value = "一級审核人员")
    private String firstUserName;
    @ApiModelProperty(value = "二級审核人员")
    private String twoUserName;
    @ApiModelProperty(value = "申请人名字")
    private String userName;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java
New file
@@ -0,0 +1,33 @@
package com.ruoyi.chargingPile.api.vo;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value="TChargingGunVO对象", description="充电枪")
public class TChargingGunVO extends TChargingGun {
    @ApiModelProperty(value = "策略名称")
    private String strategyName;
    @ApiModelProperty(value = "编辑权限")
    private boolean authUpdate = true;
    @ApiModelProperty(value = "删除权限")
    private boolean authDelete = true;
    @ApiModelProperty(value = "查看费率权限")
    private boolean authViewRates = true;
    @ApiModelProperty(value = "下载二维码权限")
    private boolean authDownloadQRCode = true;
    @ApiModelProperty(value = "查看详情权限")
    private boolean authQueryInfo = true;
    @ApiModelProperty(value = "结束充电权限")
    private boolean authEndCharge = true;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingPileVO.java
New file
@@ -0,0 +1,31 @@
package com.ruoyi.chargingPile.api.vo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
@ApiModel(value = "TChargingPileVO对象",description = "充电桩信息")
public class TChargingPileVO implements Serializable {
    @ApiModelProperty(value = "充电桩id")
    private Integer id;
    @ApiModelProperty(value = "设备编号")
    private String code;
    @ApiModelProperty(value = "充电设备名称")
    private String name;
    @ApiModelProperty(value = "桩号")
    private Integer number;
    @ApiModelProperty(value = "充电枪信息列表")
    private List<TChargingGun> chargingGunList;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/UpdateChargingPileStatusVo.java
New file
@@ -0,0 +1,15 @@
package com.ruoyi.chargingPile.api.vo;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/11/4 11:37
 */
@Data
public class UpdateChargingPileStatusVo {
    private String pile_code;
    private String gun_code;
    private Integer status;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
New file
@@ -0,0 +1,5 @@
com.ruoyi.chargingPile.api.factory.ChargingPileFallbackFactory
com.ruoyi.chargingPile.api.factory.SiteFallbackFactory
com.ruoyi.chargingPile.api.factory.ChargingGunFallbackFactory
com.ruoyi.chargingPile.api.factory.AccountingStrategyDetailFallbackFactory
com.ruoyi.chargingPile.api.factory.AccountingStrategyFallbackFactory
ruoyi-api/ruoyi-api-chargingPile/src/main/resources/template/充电桩申请记录.xlsx
Binary files differ
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java
@@ -24,4 +24,5 @@
    public static final String ACCOUNT_SERVICE = "ruoyi-account";
    public static final String OTHER_SERVICE = "ruoyi-other";
    public static final String ORDER_SERVICE = "ruoyi-order";
    public static final String CHARGINGPILE_SERVICE = "ruoyi-chargingPile";
}
ruoyi-service/pom.xml
@@ -12,6 +12,7 @@
        <module>ruoyi-account</module>
        <module>ruoyi-order</module>
        <module>ruoyi-other</module>
        <module>ruoyi-chargingPile</module>
    </modules>
    <artifactId>ruoyi-service</artifactId>
ruoyi-service/ruoyi-chargingPile/pom.xml
New file
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.ruoyi</groupId>
        <artifactId>ruoyi-service</artifactId>
        <version>3.6.2</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>ruoyi-modules-chargingPile</artifactId>
    <description>
        ruoyi-modules-chargingPile充电桩模块
    </description>
    <dependencies>
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-api-other</artifactId>
        </dependency>
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-api-order</artifactId>
        </dependency>
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-api-chargingPile</artifactId>
        </dependency>
        <!-- SpringCloud Alibaba Nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- SpringCloud Alibaba Nacos Config -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!-- SpringCloud Alibaba Sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>
        <!-- SpringBoot Actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- SpringCloud Loadbalancer -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <!-- Swagger UI -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.fox.version}</version>
        </dependency>
        <!-- Mysql Connector -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- RuoYi Common Log -->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-common-log</artifactId>
        </dependency>
        <!-- RuoYi Common Swagger -->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-common-swagger</artifactId>
        </dependency>
        <!-- 引入Druid依赖,阿里巴巴所提供的数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.3.0</version>
            <type>pom</type>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
</project>
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/RuoYiChargingPileApplication.java
New file
@@ -0,0 +1,40 @@
package com.ruoyi.chargingPile;
import com.ruoyi.common.security.annotation.EnableCustomConfig;
import com.ruoyi.common.security.annotation.EnableRyFeignClients;
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
 * 账户模块
 * @author ruoyi
 */
@EnableCustomConfig
@MapperScan({"com.ruoyi.chargingPile.mapper"})
@EnableCustomSwagger2
@EnableRyFeignClients
@SpringBootApplication
@EnableScheduling//开启定时任务
@ServletComponentScan
@EnableTransactionManagement//开启事务
public class RuoYiChargingPileApplication {
    public static void main(String[] args) {
        SpringApplication.run(RuoYiChargingPileApplication.class, args);
        System.out.println("(♥◠‿◠)ノ゙  充电桩模块启动成功   ლ(´ڡ`ლ)゙  \n" +
                " .-------.       ____     __        \n" +
                " |  _ _   \\      \\   \\   /  /    \n" +
                " | ( ' )  |       \\  _. /  '       \n" +
                " |(_ o _) /        _( )_ .'         \n" +
                " | (_,_).' __  ___(_ o _)'          \n" +
                " |  |\\ \\  |  ||   |(_,_)'         \n" +
                " |  | \\ `'   /|   `-'  /           \n" +
                " |  |  \\    /  \\      /           \n" +
                " ''-'   `'-'    `-..-'              ");
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/DataUpdateHandlerConfig.java
New file
@@ -0,0 +1,50 @@
package com.ruoyi.chargingPile.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.ruoyi.common.security.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
import java.util.Date;
/**
 * @author xiaochen
 * @ClassName DataUpdateInterceptor
 * @Description 数据更新操作处理
 * @date 2021-12-15
 * <p>
 * 注意,之前在此处注入了 JwtTokenUtils
 * <p>
 * 造成spring循环依赖,项目支棱不起来
 */
@Slf4j
@Configuration
public class DataUpdateHandlerConfig implements MetaObjectHandler {
    @Autowired
    private TokenService tokenService;
    /**
     * 新增数据执行
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
    }
    /**
     * 修改数据执行
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/FileUploadConfig.java
New file
@@ -0,0 +1,21 @@
package com.ruoyi.chargingPile.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
 * <p>文件上传配置</p>
 *
 * @author mouseyCat
 * @date 2020/10/13 16:10
 */
@Data
@Component
@ConfigurationProperties(prefix = "file.upload")
public class FileUploadConfig {
    private String accessPath;
    private String allowExt;
    private String location;
    private String qrLocation;
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/HttpConfig.java
New file
@@ -0,0 +1,25 @@
package com.ruoyi.chargingPile.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
 * http请求工具配置
 *
 * @author: KingKong
 * @create: 2018-11-14 10:47
 **/
@Configuration
public class HttpConfig {
    @Autowired
    private RestTemplateBuilder builder;
    @Bean
    public RestTemplate restTemplate() {
        return builder.build();
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/config/MybatisPlusConfig.java
New file
@@ -0,0 +1,51 @@
package com.ruoyi.chargingPile.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author xiaochen
 * @ClassName MybatisPlusConfig
 * @Description MybatisPlus相关配置
 * @date 2020-09-22 11:22、
 * 直接以实现类作为bean的注入(有事务管理的类)
 * @EnableTransactionManagement(proxyTargetClass = true)
 */
@Configuration
public class MybatisPlusConfig {
    private final DataUpdateHandlerConfig dataUpdateHandler;
    @Autowired
    public MybatisPlusConfig(DataUpdateHandlerConfig dataUpdateHandler) {
        this.dataUpdateHandler = dataUpdateHandler;
    }
    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
    /**
     * 自动填充功能
     *
     * @return
     */
    @Bean
    public GlobalConfig globalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(dataUpdateHandler);
        return globalConfig;
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java
New file
@@ -0,0 +1,258 @@
package com.ruoyi.chargingPile.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
import com.ruoyi.chargingPile.api.model.*;
import com.ruoyi.chargingPile.api.query.GetSiteList;
import com.ruoyi.chargingPile.api.query.SiteDetailQuery;
import com.ruoyi.chargingPile.api.query.SiteQuery;
import com.ruoyi.chargingPile.api.vo.*;
import com.ruoyi.chargingPile.dto.SiteDTO;
import com.ruoyi.chargingPile.service.*;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.utils.SecurityUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 19:56
 */
@RestController
@RequestMapping("/site")
public class SiteController {
    @Resource
    private ISiteService siteService;
    @Resource
    private TChargingPileService chargingPileService;
    @Resource
    private TChargingGunService chargingGunService;
    @Autowired
    private TAccountingStrategyService accountingStrategyService;
    @Autowired
    private TAccountingStrategyDetailService accountingStrategyDetailService;
    /**
     * 根据站点id 查询所有充电桩
     * @param siteId
     * @return
     */
    @GetMapping("/getPileListBySiteId/{siteId}")
    public R<List<TChargingPile>> getPileListBySiteId(@PathVariable("siteId")Integer siteId){
        return R.ok(chargingPileService.lambdaQuery().eq(TChargingPile::getSiteId, siteId).list());
    }
    /**
     * 通过桩编号获取电站信息 遠程調用
     * @param number
     * @return
     */
    @PostMapping("/getSiteInfoByNumber1")
    public R<SiteInfoVO> getSiteInfoByNumber1(@RequestParam("number") String number){
        SiteInfoVO siteInfoVO = new SiteInfoVO();
        TChargingPile one = chargingPileService.lambdaQuery().eq(TChargingPile::getCode, number).one();
        TChargingGun chargingGun = chargingGunService.getOne(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, one.getId()).last(" limit 0, 1"));
        Site site = siteService.getById(chargingGun.getSiteId());
        Integer accountingStrategyId = chargingGun.getAccountingStrategyId();
        if(null == accountingStrategyId){
            accountingStrategyId = site.getAccountingStrategyId();
        }
        TAccountingStrategy byId1 = accountingStrategyService.getById(accountingStrategyId);
        List<TAccountingStrategyDetail> list = accountingStrategyDetailService.lambdaQuery().eq(TAccountingStrategyDetail::getAccountingStrategyId, byId1.getId()).list();
        list.stream().filter(item -> "00:00".equals(item.getEndTime())).forEach(item -> item.setEndTime("23:59:59"));
        for (TAccountingStrategyDetail tAccountingStrategyDetail : list) {
            // 当前时间属于那个阶段 取哪个阶段的电价
            if(DateUtils.string2LocalTime(tAccountingStrategyDetail.getStartTime() + ":00").compareTo(LocalTime.now()) <= 0
                    && DateUtils.string2LocalTime(tAccountingStrategyDetail.getEndTime() + ("23:59:59".equals(tAccountingStrategyDetail.getEndTime())?"":":00")).compareTo(LocalTime.now()) > 0){
                siteInfoVO.setElectrovalence(tAccountingStrategyDetail.getElectrovalence().add(tAccountingStrategyDetail.getServiceCharge()).setScale(4, BigDecimal.ROUND_HALF_UP));
//                // 获取当前登录用户id
//                Long userId = tokenService.getLoginUserApplet().getUserId();
//                if(Objects.nonNull(appUser)){
////                    TVip vip = vipClient.getInfo1(appUser.getVipId()).getData();
//                    GetAppUserVipDetail getAppUserVipDetail = new GetAppUserVipDetail();
//                    getAppUserVipDetail.setAppUserId(userId);
//                    getAppUserVipDetail.setVipId(appUser.getVipId());
//                    R<TAppUserVipDetail> appUserVipDetail = vipDetailClient.getAppUserVipDetail(getAppUserVipDetail);
//                    TAppUserVipDetail data1 = appUserVipDetail.getData();
//                    if(Objects.nonNull(data1)){
//                        String vipJson = data1.getVipJson();
//                        TVip vip = JSON.parseObject(vipJson, TVip.class);
//                        if(Objects.nonNull(vip) && vip.getType() == 2){
//                            siteInfoVO.setVipElectrovalence(vip.getDiscount().divide(new BigDecimal(10)).multiply(tAccountingStrategyDetail.getServiceCharge()).add(tAccountingStrategyDetail.getElectrovalence()));
//                        }
//                    }
//                }
            }
        }
        siteInfoVO.setChargingPileId(one.getId());
        siteInfoVO.setName(site.getName());
        siteInfoVO.setNumber(one.getNumber().toString());
        siteInfoVO.setSpaceChargeExplain(site.getSpaceChargeExplain());
        return R.ok(siteInfoVO);
    }
    @GetMapping("/getSiteList")
    @ApiOperation(value = "获取站点列表", tags = {"管理后台-站点管理"})
    public AjaxResult<PageInfo<GetSiteListDTO>> getSiteList(GetSiteList siteList){
        PageInfo<GetSiteListDTO> list = siteService.getSiteList(siteList);
        return AjaxResult.success(list);
    }
    @GetMapping("/getSiteList/byUserId")
    @ApiOperation(value = "获取站点列表", tags = {"管理后台-站点管理"})
    public R<List<GetSiteListDTO>> getSiteListByUserId(@RequestParam("userId") Long userId){
        PageInfo<GetSiteListDTO> list = siteService.getSiteList1(userId);
        return R.ok(list.getRecords());
    }
    @GetMapping("/getSiteList1")
    @ApiOperation(value = "获取站点列表 不分页", tags = {"管理后台-活动费用统计"})
    public AjaxResult<List<Site>> getSiteList1(){
        return AjaxResult.success(siteService.list(new QueryWrapper<>()));
    }
    @ApiOperation(value = "获取站点分页列表", tags = {"小程序-站点管理-首页"})
    @PostMapping("/pageList")
    public AjaxResult<PageInfo<SiteVO>> pageList(@Validated @RequestBody SiteQuery query, HttpServletRequest request){
        int isLogin = StringUtils.isEmpty(SecurityUtils.getToken(request)) ? 0 : 1;
        return AjaxResult.success(siteService.pageList(query,isLogin));
    }
    @ApiOperation(value = "获取站点详细信息", tags = {"小程序-站点管理-站点详情"})
    @PostMapping("/getDetailById")
    public AjaxResult<SiteDetailVO> getDetailById(@Validated @RequestBody SiteDetailQuery query){
        SiteDetailVO siteDetailVO = siteService.getDetailById(query);
        // 查询绑定车牌提示文案
        return AjaxResult.success(siteDetailVO);
    }
    @ApiOperation(value = "获取站点下充电桩及充电枪列表", tags = {"小程序-站点管理-站点详情"})
    @GetMapping("/getChargingGunList")
    public AjaxResult<List<TChargingPileVO>> getChargingGunList(@RequestParam(value = "siteId")@ApiParam(value = "站点id", required = true)Integer siteId,
                                                                @RequestParam(value = "type",required = false)@ApiParam(value = "类型 1=超充,2=快充,3=慢充")Integer type){
        return AjaxResult.success(chargingPileService.getChargingGunList(siteId,type));
    }
    @ApiOperation(value = "获取站点下充电枪数量统计", tags = {"管理后台-数据分析-电站分析"})
    @GetMapping("/getChargingGunCount")
    public AjaxResult<Map<String,ChargingGunCountVO>> getChargingGunCount(@RequestParam(value = "siteId")@ApiParam(value = "站点id", required = true)Integer siteId){
        return AjaxResult.success(chargingGunService.getChargingGunCount(siteId));
    }
    @ApiOperation(value = "获取站点下充电枪数量统计", tags = {"小程序-站点管理-站点详情"})
    @GetMapping("/getChargingGunCount1")
    public AjaxResult<Map<String,ChargingGunCountVO>> getChargingGunCount1(@RequestParam(value = "siteId")@ApiParam(value = "站点id", required = true)Integer siteId){
        return AjaxResult.success(chargingGunService.getChargingGunCount(siteId));
    }
    @ResponseBody
    @PostMapping("/addSite")
    @ApiOperation(value = "添加站点", tags = {"管理后台-站点管理"})
    @Log(title = "【站点管理】添加站点", businessType = BusinessType.INSERT)
    public AjaxResult addSite(@RequestBody SiteDTO dto){
        return siteService.addSite(dto);
    }
    @ResponseBody
    @PostMapping("/getSiteInfo/{id}")
    @ApiOperation(value = "获取站点详情", tags = {"管理后台-站点管理"})
    public AjaxResult<Site> getSiteInfo(@PathVariable Integer id){
        Site site = siteService.getById(id);
        return AjaxResult.success(site);
    }
    @ResponseBody
    @PostMapping("/editSite")
    @ApiOperation(value = "编辑站点", tags = {"管理后台-站点管理"})
    @Log(title = "【站点管理】编辑站点", businessType = BusinessType.UPDATE)
    public AjaxResult editSite(@RequestBody Site site){
        return siteService.editSite(site);
    }
    @ResponseBody
    @DeleteMapping("/delSite")
    @ApiOperation(value = "删除站点", tags = {"管理后台-站点管理"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "站点id", name = "id", dataTypeClass = Integer.class, required = true)
    })
    @Log(title = "【站点管理】删除站点", businessType = BusinessType.DELETE)
    public AjaxResult delSite(@RequestParam("id") Integer[] id){
        return siteService.delSite(id);
    }
    @ResponseBody
    @PostMapping("/setAccountingStrategy/{id}")
    @ApiOperation(value = "设置站点计费策略", tags = {"管理后台-站点管理"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "站点id", name = "id", dataTypeClass = Integer.class, required = true),
            @ApiImplicitParam(value = "计费策略id", name = "accountingStrategyId", dataTypeClass = Integer.class, required = true)
    })
    @Log(title = "【站点管理】设置站点计费策略", businessType = BusinessType.OTHER)
    public AjaxResult setAccountingStrategy(@PathVariable("id") Integer id, @RequestParam("accountingStrategyId") Integer accountingStrategyId){
        siteService.setAccountingStrategy(id, accountingStrategyId);
        return AjaxResult.success();
    }
    @ResponseBody
    @GetMapping("/getAllSiteList")
    @ApiOperation(value = "获取所有站点数据", tags = {"管理后台-充电桩信息", "管理后台-系统用户管理", "管理后台-角色管理", "管理后台-系统通知", "管理后台-充电评价"})
    public AjaxResult<List<Site>> getAllSiteList(){
        LambdaQueryWrapper<Site> wrapper = new LambdaQueryWrapper<Site>().eq(Site::getDelFlag, 0);
        List<Site> list = siteService.list(wrapper.orderByDesc(Site::getCreateTime));
        return AjaxResult.success(list);
    }
    /**
     * 获取站点数据集合
     * @param ids
     * @return
     */
    @ResponseBody
    @PostMapping("/getSiteByIds")
    public R<List<Site>> getSiteByIds(@RequestBody List<Integer> ids){
        List<Site> sites = siteService.list(new LambdaQueryWrapper<Site>().in(Site::getId, ids).eq(Site::getDelFlag, 0));
        return R.ok(sites);
    }
    /**
     * 获取所有站点数据
     * @return
     */
    @ResponseBody
    @PostMapping("/getSiteAll")
    public R<List<Site>> getSiteAll(){
        List<Site> list = siteService.list(new LambdaQueryWrapper<Site>().eq(Site::getDelFlag, 0));
        return R.ok(list);
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java
New file
@@ -0,0 +1,382 @@
package com.ruoyi.chargingPile.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.chargingPile.api.dto.TAccountingStrategyDTO;
import com.ruoyi.chargingPile.api.model.*;
import com.ruoyi.chargingPile.api.query.TAccountingStrategyQuery;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyDetailVO;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyVO;
import com.ruoyi.chargingPile.service.ISiteService;
import com.ruoyi.chargingPile.service.TAccountingStrategyDetailService;
import com.ruoyi.chargingPile.service.TAccountingStrategyService;
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.dto.SteategyPassDto;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.log.enums.OperatorType;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.feignClient.SysUserClient;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
 * <p>
 * 计费策略 前端控制器
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@RestController
@RequestMapping("/t-accounting-strategy")
public class TAccountingStrategyController {
    private final TAccountingStrategyService accountingStrategyService;
    private final TAccountingStrategyDetailService accountingStrategyDetailService;
    @Autowired
    private TChargingPileService chargingPileService;
    @Autowired
    private ISiteService siteService;
    @Resource
    private SysUserClient sysUserClient;
    @Autowired
    public TAccountingStrategyController(TAccountingStrategyService accountingStrategyService, TAccountingStrategyDetailService accountingStrategyDetailService) {
        this.accountingStrategyService = accountingStrategyService;
        this.accountingStrategyDetailService = accountingStrategyDetailService;
    }
    /**
     * 查询计费策略列表
     */
    @ApiOperation(tags = {"后台-计费策略"},value = "查询计费策略分页列表")
    @PostMapping(value = "/pageList")
    public AjaxResult<PageInfo<TAccountingStrategyVO>> pageList(@RequestBody TAccountingStrategyQuery query) {
        return AjaxResult.ok(accountingStrategyService.pageList(query));
    }
    /**
     * 查询计费策略明细列表
     */
    @ApiOperation(tags = {"后台-计费策略", "管理后台-站点管理", "管理后台-充电桩信息"},value = "查询计费策略明细列表")
    @GetMapping(value = "/queryAccountingStrategyDetailByStrategyId")
    public AjaxResult<List<TAccountingStrategyDetailVO>> queryAccountingStrategyDetailByStrategyId(@RequestParam("strategyId") Integer strategyId) {
        List<TAccountingStrategyDetailVO> list = accountingStrategyDetailService.queryMangementAccountingStrategyDetailByStrategyId(strategyId);
        list.forEach(detail -> {
            detail.setTotalPrice(detail.getElectrovalence().add(detail.getServiceCharge()));
        });
        return AjaxResult.ok(list);
    }
    /**
     * 添加计费策略管理
     */
    @ApiOperation(tags = {"后台-计费策略", "管理后台-站点管理"},value = "添加计费策略")
    @PostMapping(value = "/add")
    @Log(title = "【计费策略】添加计费策略", businessType = BusinessType.INSERT)
    public AjaxResult<Integer> add(@RequestBody TAccountingStrategyDTO dto) {
        if(null != dto.getSiteId()){
            dto.setAuditStatus(3);
        }
        Boolean flag = accountingStrategyDetailService.isStrategy24Hour(dto.getAccountingStrategyDetails());
        if(flag){
            return AjaxResult.error("计费模板时间设置有误差");
        }
        // 判断同阶段是否价格不一致
        Boolean flag1 = accountingStrategyDetailService.isStrategyPriceConsistent(dto.getAccountingStrategyDetails());
        if(!flag1){
            return AjaxResult.error("同阶段费率值需一致");
        }
        Long userId = SecurityUtils.getLoginUser().getUserid();
        dto.setUserId(userId);
        dto.setAuditStatus(3);
        accountingStrategyService.save(dto);
        // 添加明细
        dto.getAccountingStrategyDetails().forEach(detail -> detail.setAccountingStrategyId(dto.getId()));
        accountingStrategyDetailService.saveBatch(dto.getAccountingStrategyDetails());
        return AjaxResult.ok(dto.getId());
    }
    /**
     * 修改计费策略
     */
    @Log(title = "【计费策略】修改计费策略", businessType = BusinessType.UPDATE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-计费策略", "管理后台-站点管理"},value = "修改计费策略")
    @PostMapping(value = "/update")
    public AjaxResult<String> update(@RequestBody TAccountingStrategyDTO dto) {
        Boolean flag = accountingStrategyDetailService.isStrategy24Hour(dto.getAccountingStrategyDetails());
        if(flag){
            return AjaxResult.error("计费模板时间设置有误差");
        }
        // 判断同阶段是否价格不一致
        Boolean flag1 = accountingStrategyDetailService.isStrategyPriceConsistent(dto.getAccountingStrategyDetails());
        if(!flag1){
            return AjaxResult.error("同阶段费率值需一致");
        }
        // 删除计费策略明细信息
        accountingStrategyDetailService.remove(Wrappers.lambdaQuery(TAccountingStrategyDetail.class)
                .eq(TAccountingStrategyDetail::getAccountingStrategyId, dto.getId()));
        accountingStrategyService.updateById(dto);
        // 添加明细
        dto.getAccountingStrategyDetails().forEach(detail -> {
            detail.setAccountingStrategyId(dto.getId());
            detail.setId(null);
        });
        accountingStrategyDetailService.saveBatch(dto.getAccountingStrategyDetails());
        return AjaxResult.success();
    }
    /**
     * 查看计费策略详情
     */
    @ApiOperation(tags = {"后台-计费策略", "管理后台-站点管理"},value = "查看计费策略详情")
    @GetMapping(value = "/getDetailById")
    public AjaxResult<TAccountingStrategyVO> getDetailById(@RequestParam("id") Integer id) {
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(id);
        TAccountingStrategyVO accountingStrategyVO = new TAccountingStrategyVO();
        BeanUtils.copyProperties(accountingStrategy,accountingStrategyVO);
        // 查询用户信息
//        if(null != accountingStrategy.getFirstUserId()){
//            String firstUserName = sysUserClient.getSysUser(accountingStrategy.getFirstUserId()).getData().getNickName();
//            accountingStrategyVO.setFirstUserName(firstUserName);
//        }
//        if(null != accountingStrategy.getTwoUserId()){
//            String twoUserName = sysUserClient.getSysUser(accountingStrategy.getTwoUserId()).getData().getNickName();
//            accountingStrategyVO.setTwoUserName(twoUserName);
//        }
        return AjaxResult.ok(accountingStrategyVO);
    }
    /**
     * 查看计费策略详情-修改后
     */
    @ApiOperation(tags = {"后台-计费策略", "管理后台-站点管理"},value = "查看计费策略详情修改后children的数据")
    @GetMapping(value = "/getDetailChildrenById")
    public AjaxResult<List<TAccountingStrategyDetail>> getDetailChildrenById(@RequestParam("id") Integer id) {
        List<TAccountingStrategyDetail> list = accountingStrategyDetailService.list(Wrappers.lambdaQuery(TAccountingStrategyDetail.class)
                .eq(TAccountingStrategyDetail::getAccountingStrategyId, id).eq(TAccountingStrategyDetail::getDelFlag, 0));
        return AjaxResult.ok(list);
    }
    /**
     * 删除计费策略
     */
    @Log(title = "【计费策略】删除计费策略", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-计费策略"},value = "删除计费策略")
    @DeleteMapping(value = "/deleteById")
    public AjaxResult<Boolean> deleteById(@RequestParam("id") Integer id) {
        // 判断策略是否在使用
        long count = siteService.count(Wrappers.lambdaQuery(Site.class)
                .eq(Site::getAccountingStrategyId, id));
        if(count>0){
            return AjaxResult.error("该计费策略正在使用中,无法删除");
        }
        // 刪除计费策略明细信息
        accountingStrategyDetailService.remove(Wrappers.lambdaQuery(TAccountingStrategyDetail.class)
                .eq(TAccountingStrategyDetail::getAccountingStrategyId, id));
        return AjaxResult.ok(accountingStrategyService.removeById(id));
    }
    /**
     * 批量删除计费策略
     */
    @Log(title = "【计费策略】批量删除计费策略", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-计费策略"},value = "批量删除计费策略")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        // 判断策略是否在使用
        long count = siteService.count(Wrappers.lambdaQuery(Site.class)
                .in(Site::getAccountingStrategyId, Arrays.asList(split)));
        if(count>0){
            return AjaxResult.error("该计费策略正在使用中,无法删除");
        }
        // 刪除计费策略明细信息
        accountingStrategyDetailService.remove(Wrappers.lambdaQuery(TAccountingStrategyDetail.class)
                .in(TAccountingStrategyDetail::getAccountingStrategyId, Arrays.asList(split)));
        return AjaxResult.success(accountingStrategyService.removeByIds(Arrays.asList(split)));
    }
    @ApiOperation(tags = {"管理后台-站点管理"},value = "获取平台添加的计费策略")
    @DeleteMapping(value = "/getPlatformAccountingStrategy")
    public AjaxResult<List<TAccountingStrategyVO>> getPlatformAccountingStrategy(){
        List<TAccountingStrategyVO> list = accountingStrategyService.getPlatformAccountingStrategy();
        return AjaxResult.success(list);
    }
    @ApiOperation(tags = {"后台-申请表单-计费模板审核"},value = "查询计费审核分页列表")
    @PostMapping(value = "/auth/pageList")
    public AjaxResult<PageInfo<TAccountingStrategyVO>> authPageList(@RequestBody TAccountingStrategyQuery query) {
        return AjaxResult.ok(accountingStrategyService.pageList1(query));
    }
    @ApiOperation(tags = {"后台-申请表单-计费模板审核"},value = "审核")
    @PostMapping(value = "/auth/pass")
    @Log(title = "【计费模板审核】审核计费模板", businessType = BusinessType.OTHER,operatorType = OperatorType.MANAGE)
    public AjaxResult<PageInfo<TAccountingStrategyVO>> authPass(@RequestBody SteategyPassDto steategyPassDto) {
        TAccountingStrategy byId = accountingStrategyService.getById(steategyPassDto.getId());
        Long userId = SecurityUtils.getLoginUser().getUserid();
        if (byId.getAuditStatus()==1&&byId.getFirstUserId()!=userId){
            return AjaxResult.error("您不是一级审核人员,无法审核");
        }
        if (byId.getAuditStatus()==2&&byId.getTwoUserId()!=userId){
            return AjaxResult.error("您不是二级审核人员,无法审核");
        }
        if (steategyPassDto.getPass()==1){
            if (byId.getAuditStatus()==1){
                byId.setAuditStatus(2);
                byId.setFirstRemark(steategyPassDto.getRemark());
                byId.setFirstAuditTime(LocalDateTime.now());
            }else if (byId.getAuditStatus()==2){
                byId.setAuditStatus(3);
                byId.setTwoRemark(steategyPassDto.getRemark());
                byId.setTwoAuditTime(LocalDateTime.now());
                //如果parentId不为空,则将parentId对应的siteId改为现在的,并且将parenId对应的数据删除
                if (byId.getParentId()!=null) {
                    TAccountingStrategy one = accountingStrategyService.lambdaQuery().eq(TAccountingStrategy::getId, byId.getParentId()).one();
                    byId.setSiteId(one.getSiteId());
                    //将site表对应的模板id修改为新的这个
                    List<Site> list = siteService.lambdaQuery().eq(Site::getAccountingStrategyId, one.getId()).list();
                    for (Site site : list) {
                        site.setAccountingStrategyId(byId.getId());
                    }
                    siteService.updateBatchById(list);
                    accountingStrategyService.removeById(one.getId());
                }
            }
        }else {
            if (byId.getAuditStatus()==1){
                byId.setFirstRemark(steategyPassDto.getRemark());
            }else if (byId.getAuditStatus()==2){
                byId.setTwoRemark(steategyPassDto.getRemark());
                byId.setTwoAuditTime(LocalDateTime.now());
            }
            byId.setAuditStatus(4);
        }
        accountingStrategyService.updateById(byId);
        return AjaxResult.success();
    }
    @ApiOperation(tags = {"后台-申请表单-计费模板审核"},value = "删除")
    @DeleteMapping(value = "/delete")
    @Log(title = "【计费模板审核】删除计费模板审核", businessType = BusinessType.DELETE)
    public R delete(String ids) {
        String[] split = ids.split(",");
        for (String s : split) {
            accountingStrategyService.removeById(s);
        }
        return R.ok();
    }
    /**
     * 小程序远程调用 根据会员折扣、预付金额 计算服务费
     * @return
     */
    @PostMapping(value = "/getServiceMoney")
    public R<BigDecimal> getServiceMoney(@RequestParam("param") String param){
        // 桩编号 + 是否是会员 + 内部会员折扣金额 + 普通会员最高折扣金额 + 预付金额
        String[] split = param.split("-");
        // 根据桩编号 查询电站
        TChargingPile one = chargingPileService.lambdaQuery().eq(TChargingPile::getNumber, split[0]).one();
        Site byId = siteService.getById(one.getSiteId());
        // 计费策略
        TAccountingStrategy one1 = accountingStrategyService.lambdaQuery().eq(TAccountingStrategy::getSiteId, byId.getId())
                .eq(TAccountingStrategy::getAuditStatus, 3).one();
        // 会员折扣
        BigDecimal discount = one1.getDiscount();
        List<TAccountingStrategyDetail> list = accountingStrategyDetailService.lambdaQuery().eq(TAccountingStrategyDetail::getAccountingStrategyId, one1.getId())
                        .eq(TAccountingStrategyDetail::getDelFlag, 0).list();
        // 当前时间属于哪个计费策略
        LocalTime now = LocalTime.now();
        // 电价
        BigDecimal electronic = new BigDecimal(BigInteger.ZERO);
        // 最终服务费
        BigDecimal serviceMoney = new BigDecimal(BigInteger.ZERO);
        // 预付金额
        BigDecimal beforeMoney = new BigDecimal(split[4]);
        // 普通会员最高折扣金额
        BigDecimal discountMoney = new BigDecimal(split[3]);
        // 内部会员折扣
        BigDecimal discountInner = new BigDecimal(split[2]);
        // 最终服务费
        BigDecimal res = new BigDecimal(BigInteger.ZERO);
        for (TAccountingStrategyDetail tAccountingStrategyDetail : list) {
            if (now.isAfter(LocalTime.parse(tAccountingStrategyDetail.getStartTime())) && now.isBefore(LocalTime.parse(tAccountingStrategyDetail.getEndTime()))){
                electronic = tAccountingStrategyDetail.getElectrovalence();
                // 非会员下的服务费
                BigDecimal multiply = beforeMoney.multiply(tAccountingStrategyDetail.getServiceCharge()).divide(electronic, 2, RoundingMode.HALF_UP);
                if (byId.getBusinessCategory() == 1){
                    // 直营才享受会员折扣
                    // 根据电价和预付金额 是否有会员折扣 计算最终服务费
                    if (split[1].equals("1")){
                        // 抵扣金额
                        BigDecimal multiply1 = multiply.multiply(discount);
                        if (multiply1.compareTo(discountMoney)>0){
                            multiply1 = discountMoney;
                        }
                        // 普通最终服务费
                        res = multiply.subtract(multiply1);
                    }
                    if (split[1].equals("2")){
                        // 内部会员折扣 最终服务费
                        res = discountInner.multiply(multiply);
                    }
                }else{
                    // 非直营
                    res = multiply;
                }
                break;
            }
        }
        return R.ok(res);
    }
    /**
     * 根据id查询数据
     * @param id
     * @return
     */
    @PostMapping(value = "/getAccountingStrategyById")
    public R<TAccountingStrategy> getAccountingStrategyById(@RequestParam("id") Integer id) {
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(id);
        return R.ok(accountingStrategy);
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyDetailController.java
New file
@@ -0,0 +1,231 @@
package com.ruoyi.chargingPile.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.chargingPile.api.dto.CheckChargingStrategyDTO;
import com.ruoyi.chargingPile.api.model.*;
import com.ruoyi.chargingPile.api.vo.StrategyPriceVO;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyDetailVO;
import com.ruoyi.chargingPile.service.*;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
/**
 * <p>
 * 计费策略明细 前端控制器
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Api(tags = "计费策略明细")
@RestController
@RequestMapping("/t-accounting-strategy-detail")
public class TAccountingStrategyDetailController {
    private final ISiteService siteService;
    private final TChargingPileService chargingPileService;
    private final TChargingGunService chargingGunService;
    private final TAccountingStrategyService accountingStrategyService;
    private final TAccountingStrategyDetailService accountingStrategyDetailService;
    @Autowired
    public TAccountingStrategyDetailController(ISiteService siteService, TChargingPileService chargingPileService, TChargingGunService chargingGunService, TAccountingStrategyService accountingStrategyService, TAccountingStrategyDetailService accountingStrategyDetailService) {
        this.siteService = siteService;
        this.chargingPileService = chargingPileService;
        this.chargingGunService = chargingGunService;
        this.accountingStrategyService = accountingStrategyService;
        this.accountingStrategyDetailService = accountingStrategyDetailService;
    }
    /**
     * 通过电站id查询计费策略明细列表
     */
    @ApiOperation(tags = {"小程序-站点管理-站点详情"},value = "通过站点id查询计费策略明细列表")
    @GetMapping(value = "/queryAccountingStrategyDetailBySiteId")
    public AjaxResult<List<TAccountingStrategyDetailVO>> queryAccountingStrategyDetailBySiteId(@RequestParam("siteId") Integer siteId) {
        Site site = siteService.getById(siteId);
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(site.getAccountingStrategyId());
        if(Objects.isNull(accountingStrategy)){
            throw new ServiceException("未查询到计费策略");
        }
        return AjaxResult.ok(accountingStrategyDetailService.queryAccountingStrategyDetailByStrategyId(accountingStrategy.getId()));
    }
    /**
     * 通过站点id查询当前时间段计费策略展示
     */
    @ApiOperation(tags = {"小程序-站点管理-站点详情"},value = "通过站点id查询当前时间段计费策略展示")
    @GetMapping(value = "/queryStrategyBySiteIdAndTime")
    public AjaxResult<List<TAccountingStrategyDetailVO>> queryStrategyBySiteIdAndTime(@RequestParam("siteId") Integer siteId) {
        return AjaxResult.ok(accountingStrategyDetailService.queryStrategyBySiteIdAndTime(siteId));
    }
    /**
     * 通过站点id查询当前时间段计费策略展示
     */
    @ApiOperation(tags = {"小程序-站点管理-站点详情"},value = "通过枪id查询当前时间段计费策略展示")
    @GetMapping(value = "/queryStrategyByGunIdAndTime")
    public AjaxResult<List<TAccountingStrategyDetailVO>> queryStrategyByGunIdAndTime(@RequestParam("gunId") Integer gunId) {
        return AjaxResult.ok(accountingStrategyDetailService.queryStrategyByGunIdAndTime(gunId));
    }
    /**
     * 价格说明金额返回,会员开通金额说明
     */
    @ApiOperation(tags = {"小程序-站点管理-站点详情"},value = "价格说明金额返回,会员开通金额说明")
    @GetMapping(value = "/queryPrice")
    public AjaxResult<StrategyPriceVO> queryPrice(@RequestParam("siteId") Integer siteId) {
        return AjaxResult.ok(accountingStrategyDetailService.queryPrice(siteId));
    }
    /**
     * 通过站点id查询当前时段使用的策略明细
     * @param siteId
     * @return
     */
    @GetMapping("/getDetailBySiteId")
    public R<TAccountingStrategyDetail> getDetailBySiteId(@RequestParam("siteId") Integer siteId){
        Site site = siteService.getById(siteId);
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(site.getAccountingStrategyId());
        List<TAccountingStrategyDetail> list = accountingStrategyDetailService.list(Wrappers.<TAccountingStrategyDetail>lambdaQuery()
                .eq(TAccountingStrategyDetail::getAccountingStrategyId, accountingStrategy.getId()));
        list.stream().filter(item -> "00:00".equals(item.getEndTime())).forEach(item -> item.setEndTime("23:59:59"));
        for (TAccountingStrategyDetail accountingStrategyDetail : list) {
            if(DateUtils.string2LocalTime(accountingStrategyDetail.getStartTime() + ":00").compareTo(LocalTime.now()) <= 0
                    && DateUtils.string2LocalTime(accountingStrategyDetail.getEndTime() + ("23:59:59".equals(accountingStrategyDetail.getEndTime())?"":":00")).compareTo(LocalTime.now()) > 0){
                return R.ok(accountingStrategyDetail);
            }
        }
        return R.ok();
    }
    /**
     * 通过桩id查询当前时段使用的策略明细
     * @param code 设备编号
     * @return
     */
    @GetMapping("/getDetailByCode")
    public R<TAccountingStrategyDetail> getDetailByCode(@RequestParam("code") String code){
        // 查询桩
        TChargingPile chargingPile = chargingPileService.getOne(Wrappers.lambdaQuery(TChargingPile.class)
                .eq(TChargingPile::getCode,code).eq(TChargingPile::getDelFlag, 0)
                .last("LIMIT 1"));
        if(Objects.isNull(chargingPile)){
            return R.fail("未查询到该桩设备");
        }
        TChargingGun chargingGun = chargingGunService.getOne(Wrappers.lambdaQuery(TChargingGun.class)
                .eq(TChargingGun::getChargingPileId, chargingPile.getId()).eq(TChargingGun::getDelFlag, 0)
                .last("LIMIT 1"));
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(chargingGun.getAccountingStrategyId());
        TAccountingStrategyDetail one = null;
        if(Objects.nonNull(accountingStrategy)){
            List<TAccountingStrategyDetail> list = accountingStrategyDetailService.list(Wrappers.<TAccountingStrategyDetail>lambdaQuery()
                    .eq(TAccountingStrategyDetail::getAccountingStrategyId, accountingStrategy.getId()));
            list.stream().filter(item -> "00:00".equals(item.getEndTime())).forEach(item -> item.setEndTime("23:59:59"));
            for (TAccountingStrategyDetail accountingStrategyDetail : list) {
                if(DateUtils.string2LocalTime(accountingStrategyDetail.getStartTime() + ":00").compareTo(LocalTime.now()) <= 0
                        && DateUtils.string2LocalTime(accountingStrategyDetail.getEndTime() + ("23:59:59".equals(accountingStrategyDetail.getEndTime())?"":":00")).compareTo(LocalTime.now()) > 0){
                    return R.ok(accountingStrategyDetail);
                }
            }
        }else {
            Site site = siteService.getById(chargingPile.getSiteId());
            accountingStrategy = accountingStrategyService.getById(site.getAccountingStrategyId());
            List<TAccountingStrategyDetail> list = accountingStrategyDetailService.list(Wrappers.<TAccountingStrategyDetail>lambdaQuery()
                    .eq(TAccountingStrategyDetail::getAccountingStrategyId, accountingStrategy.getId()));
            list.stream().filter(item -> "00:00".equals(item.getEndTime())).forEach(item -> item.setEndTime("23:59:59"));
            for (TAccountingStrategyDetail accountingStrategyDetail : list) {
                if(DateUtils.string2LocalTime(accountingStrategyDetail.getStartTime() + ":00").compareTo(LocalTime.now()) <= 0
                        && DateUtils.string2LocalTime(accountingStrategyDetail.getEndTime() + ("23:59:59".equals(accountingStrategyDetail.getEndTime())?"":":00")).compareTo(LocalTime.now()) > 0){
                    return R.ok(accountingStrategyDetail);
                }
            }
        }
        return R.ok();
    }
    /**
     * 校验充电桩计费模版是否准确
     * @param
     * @return
     */
    @PostMapping("/checkChargingStrategy")
    public R<Boolean> checkChargingStrategy(@RequestBody CheckChargingStrategyDTO dto){
        // 查询桩
        TChargingPile chargingPile = chargingPileService.getOne(Wrappers.lambdaQuery(TChargingPile.class)
                .eq(TChargingPile::getCode,dto.getCode()).eq(TChargingPile::getDelFlag, 0)
                .last("LIMIT 1"));
        if(Objects.isNull(chargingPile)){
            return R.ok(false);
        }
        Site site = siteService.getById(chargingPile.getSiteId());
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(site.getAccountingStrategyId());
        if(null == accountingStrategy){
            List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, chargingPile.getId()));
            accountingStrategy = accountingStrategyService.getById(list.get(0).getAccountingStrategyId());
        }
        TAccountingStrategyDetail one = accountingStrategyDetailService.getOne(Wrappers.<TAccountingStrategyDetail>lambdaQuery()
                .eq(TAccountingStrategyDetail::getAccountingStrategyId, accountingStrategy.getId())
                .last(" and DATE_FORMAT(now(), '%H:%i') between start_time and (if(end_time = '00:00', '23:59', end_time))"));
        return R.ok(dto.getStrategyDetailId().equals(one.getId()));
    }
    /**
     * 根据计费策略主表id策略明细
     * @param id
     * @return
     */
    @GetMapping("/getListByAccountingStrategyId")
    public R<List<TAccountingStrategyDetail>> getListByAccountingStrategyId(@RequestParam("id") Integer id){
        List<TAccountingStrategyDetail> list = accountingStrategyDetailService.list(new LambdaQueryWrapper<TAccountingStrategyDetail>()
                .eq(TAccountingStrategyDetail::getAccountingStrategyId, id).orderByAsc(TAccountingStrategyDetail::getStartTime));
        return R.ok(list);
    }
    /**
     * 通过桩编号查询当前使用的策略明细列表
     * @param code
     * @return
     */
    @GetMapping("/getDetailListByCode")
    public R<List<TAccountingStrategyDetail>> getDetailListByCode(@RequestParam("code") String code){
        // 查询桩
        TChargingPile chargingPile = chargingPileService.getOne(Wrappers.lambdaQuery(TChargingPile.class)
                .eq(TChargingPile::getCode,code).eq(TChargingPile::getDelFlag, 0)
                .last("LIMIT 1"));
        if(Objects.isNull(chargingPile)){
            return R.fail("未查询到该桩设备");
        }
        TChargingGun chargingGun = chargingGunService.getOne(Wrappers.lambdaQuery(TChargingGun.class)
                .eq(TChargingGun::getChargingPileId, chargingPile.getId()).eq(TChargingGun::getDelFlag, 0)
                .last("LIMIT 1"));
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(chargingGun.getAccountingStrategyId());
        if(Objects.nonNull(accountingStrategy)){
            List<TAccountingStrategyDetail> accountingStrategyDetails = accountingStrategyDetailService.list(Wrappers.<TAccountingStrategyDetail>lambdaQuery()
                    .eq(TAccountingStrategyDetail::getAccountingStrategyId, accountingStrategy.getId()));
            return R.ok(accountingStrategyDetails);
        }else {
            Site site = siteService.getById(chargingPile.getSiteId());
            accountingStrategy = accountingStrategyService.getById(site.getAccountingStrategyId());
            List<TAccountingStrategyDetail> accountingStrategyDetails = accountingStrategyDetailService.list(Wrappers.<TAccountingStrategyDetail>lambdaQuery()
                    .eq(TAccountingStrategyDetail::getAccountingStrategyId, accountingStrategy.getId()));
            return R.ok(accountingStrategyDetails);
        }
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java
New file
@@ -0,0 +1,333 @@
package com.ruoyi.chargingPile.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
import com.ruoyi.chargingPile.api.dto.TChargingGunDTO;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.query.TChargingGunQuery;
import com.ruoyi.chargingPile.api.vo.*;
import com.ruoyi.chargingPile.config.FileUploadConfig;
import com.ruoyi.chargingPile.service.ISiteService;
import com.ruoyi.chargingPile.service.TChargingGunService;
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.chargingPile.util.QRCodeUtils;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.log.enums.OperatorType;
import com.ruoyi.common.security.annotation.Logical;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.service.TokenService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
 * 充电枪 前端控制器
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Api(tags = "充电枪")
@RestController
@RequestMapping("/t-charging-gun")
public class TChargingGunController {
    @Autowired
    private TChargingGunService chargingGunService;
    @Resource
    private TChargingPileService chargingPileService;
    @Resource
    private ISiteService siteService;
    @Autowired
    private FileUploadConfig fileUploadConfig;
    /**
     * 查询所有枪
     */
    @PostMapping(value = "/getAllGun")
    public R<List<TChargingGun>> getAllGun() {
        return R.ok(chargingGunService.list());
    }
    /**
     * 查询所有桩
     */
    @PostMapping(value = "/getAllPile")
    public R<List<TChargingPile>> getAllPile() {
        return R.ok(chargingPileService.list());
    }
    /**
     * 查询充电枪列表
     */
    @RequiresPermissions(value = {"/chargingPile", "/chargingGun"}, logical = Logical.OR)
    @ApiOperation(tags = {"后台-充电枪", "管理后台-充电桩信息"},value = "查询充电枪分页列表")
    @PostMapping(value = "/pageList")
    public AjaxResult<PageInfo<TChargingGunVO>> pageList(@RequestBody TChargingGunQuery query) {
        return AjaxResult.ok(chargingGunService.pageList(query));
    }
    /**
     * 添加充电枪管理
     */
    @RequiresPermissions(value = {"/chargingPile/add_charging_gun"}, logical = Logical.OR)
    @Log(title = "【充电桩信息】添加充电枪", businessType = BusinessType.INSERT,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"管理后台-充电桩信息"},value = "添加充电枪")
    @PostMapping(value = "/add")
    public AjaxResult add(@RequestBody TChargingGunDTO dto) {
        return chargingGunService.add(dto);
    }
    /**
     * 修改充电枪
     */
    @RequiresPermissions(value = {"/chargingGun/update"}, logical = Logical.OR)
    @Log(title = "【充电桩信息】修改充电枪", businessType = BusinessType.UPDATE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"管理后台-充电桩信息"},value = "修改充电枪")
    @PostMapping(value = "/update")
    public AjaxResult update(@RequestBody TChargingGunDTO dto) {
        return chargingGunService.update(dto);
    }
    /**
     * 查看充电枪详情
     */
    @RequiresPermissions(value = {"/chargingGun/update", "/chargingGun/select"}, logical = Logical.OR)
    @ApiOperation(tags = {"后台-充电枪", "管理后台-充电桩信息"},value = "查看充电枪详情")
    @GetMapping(value = "/getDetailById")
    public AjaxResult<TChargingGun> getDetailById(@RequestParam("id") Integer id) {
        return AjaxResult.ok(chargingGunService.getById(id));
    }
    /**
     * 删除充电枪
     */
    @RequiresPermissions(value = {"/chargingGun/del"}, logical = Logical.OR)
    @Log(title = "【充电桩信息】删除充电枪", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"管理后台-充电桩信息"},value = "删除充电枪")
    @DeleteMapping(value = "/deleteById")
    public AjaxResult<Boolean> deleteById(@RequestParam("id") Integer id) {
        TChargingGun chargingGun = chargingGunService.getById(id);
        chargingGunService.removeById(chargingGun);
        return AjaxResult.success();
    }
    /**
     * 批量删除充电枪
     */
    @RequiresPermissions(value = {"/chargingGun/del"}, logical = Logical.OR)
    @Log(title = "【充电桩信息】批量删除充电枪", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-充电枪"},value = "批量删除充电枪")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        return AjaxResult.ok(chargingGunService.removeByIds(Arrays.asList(split)));
    }
    @RequiresPermissions(value = {"/chargingGun/download_qr_code"}, logical = Logical.OR)
    @ApiOperation(tags = {"管理后台-充电桩信息"},value = "下载二维码")
    @GetMapping(value = "/downloadQRCode/{id}")
    @Log(title = "【充电桩信息】下载二维码", businessType = BusinessType.OTHER,operatorType = OperatorType.MANAGE)
    public void downloadQRCode(@PathVariable Integer id, HttpServletResponse response){
        try {
            TChargingGun chargingGun = chargingGunService.getById(id);
            TChargingPile chargingPile = chargingPileService.getById(chargingGun.getChargingPileId());
            String code = chargingPile.getCode() + chargingGun.getCode();
            String fileName = URLEncoder.encode(code, "UTF-8") + ".jpg";
            response.setContentType("application/force-download");
            response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
            String url = "https://mxcd.zhinenganguan.com?No=" + code;
            String filePath = fileUploadConfig.getLocation() + fileName;
            QRCodeUtils.encode(url, filePath);
            FileInputStream inputStream = new FileInputStream(filePath);
            ServletOutputStream out = response.getOutputStream();
            int len = 0;
            byte[] buf = new byte[1024];
            while ((len = inputStream.read(buf, 0, 1024)) != -1) {
                out.write(buf);
            }
            out.flush();
            out.close();
            inputStream.close();
            //清除服务器上的文件
            try {
                // 使用Runtime执行命令
                Process process = Runtime.getRuntime().exec("sudo rm -rf " + filePath);
                // 读取命令的输出
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
                // 等待命令执行完成
                process.waitFor();
                // 关闭流
                reader.close();
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Resource
    private TokenService tokenService;
    /**
     * 设备状态统计
     */
    @RequiresPermissions(value = {"/workbench"}, logical = Logical.OR)
    @ApiOperation(tags = {"后台-工作台"},value = "设备状态统计")
    @PutMapping(value = "/gunStatusStatistics")
    public R<GunStatusStatisticsVO> gunStatusStatistics() {
        List<Integer> siteIds = new ArrayList<>();
        Long userId = tokenService.getLoginUser().getUserid();
        //获取当前登录的siteIds
        PageInfo<GetSiteListDTO> siteList1 = siteService.getSiteList1(userId);
        for (GetSiteListDTO datum : siteList1.getRecords()) {
            siteIds.add(datum.getId());
        }
        return R.ok(chargingGunService.gunStatusStatistics(siteIds));
    }
    /**
     * 根据id获取充电枪完整名称
     * @param id
     * @return
     */
    @ResponseBody
    @PostMapping(value = "/getAllName/{id}")
    public R<String> getAllName(@PathVariable Integer id){
        TChargingGun chargingGun = chargingGunService.getById(id);
        TChargingPile chargingPile = chargingPileService.getById(chargingGun.getChargingPileId());
        return R.ok(chargingPile.getName() + chargingGun.getName());
    }
    /**
     * 根据id获取充电枪详情
     * @param id
     * @return
     */
    @ResponseBody
    @PostMapping(value = "/getChargingGunById/{id}")
    public R<TChargingGun> getChargingGunById(@PathVariable Integer id){
        TChargingGun chargingGun = chargingGunService.getById(id);
        return R.ok(chargingGun);
    }
    /**
     * 根据id获取充电枪详情
     * @param id
     * @return
     */
    @ResponseBody
    @PostMapping(value = "/getAllInfoById/{id}")
    public R<SiteNameVO> getAllInfoById(@PathVariable Integer id){
        SiteNameVO siteNameVO = new SiteNameVO();
        TChargingGun chargingGun = chargingGunService.getById(id);
        siteNameVO.setGunName(chargingGun.getName());
        siteNameVO.setGunNumber(chargingGun.getCode());
        TChargingPile chargingPile = chargingPileService.getById(chargingGun.getChargingPileId());
        siteNameVO.setPileName(chargingPile.getName());
        siteNameVO.setPileNumber(chargingPile.getNumber());
        Site site = siteService.getById(chargingGun.getSiteId());
        siteNameVO.setSiteName(site.getName());
        return R.ok(siteNameVO);
    }
    /**
     * 根据枪编号获取充电枪
     * @param code
     * @return
     */
    @PostMapping("/getChargingGunByCode")
    public R<TChargingGun> getChargingGunByCode(@RequestBody GetChargingGunByCode code){
        TChargingPile chargingPile = chargingPileService.getOne(new LambdaQueryWrapper<TChargingPile>()
                .eq(TChargingPile::getCode, code.getCharging_pile_code()).eq(TChargingPile::getDelFlag, 0));
        return R.ok(chargingGunService.getOne(Wrappers.lambdaQuery(TChargingGun.class)
                        .eq(TChargingGun::getChargingPileId, chargingPile.getId())
                        .eq(TChargingGun::getCode, code.getCharging_gun_code())
                        .eq(TChargingGun::getDelFlag, 0)
                        .last("LIMIT 1")));
    }
    /**
     * 根据枪编号获取充电枪
     * @param code
     * @return
     */
    /**
     * 编辑充电枪
     * @param chargingGun
     * @return
     */
    @PostMapping("/updateChargingGunById")
    public R<String> updateChargingGunById(@RequestBody TChargingGun chargingGun){
        chargingGunService.updateById(chargingGun);
        return R.ok();
    }
    /**
     * 根据充电桩id获取枪
     * @param chargingPileId
     * @return
     */
    @PostMapping("/getChargingGunByChargingPileId")
    public R<List<TChargingGun>> getChargingGunByChargingPileId(@RequestParam("chargingPileId") Integer chargingPileId){
        List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, chargingPileId)
                .eq(TChargingGun::getDelFlag, 0));
        return R.ok(list);
    }
    /**
     * 根据充电桩ids获取枪
     * @param chargingPileIds
     * @return
     */
    @PostMapping("/getChargingGunByChargingPileIds")
    public R<List<TChargingGun>> getChargingGunByChargingPileIds(@RequestParam("chargingPileIds") List<Integer> chargingPileIds){
        List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().in(TChargingGun::getChargingPileId, chargingPileIds)
                .eq(TChargingGun::getDelFlag, 0));
        return R.ok(list);
    }
    /**
     * 根据枪唯一码查询信息
     * @return
     */
    @PostMapping("/getChargingGunByFullNumber")
    public R<TChargingGun> getChargingGunByFullNumber(@RequestParam("fullNumber") String fullNumber){
        TChargingGun chargingGun = chargingGunService.getOne(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getDelFlag, 0).eq(TChargingGun::getFullNumber, fullNumber));
        return R.ok(chargingGun);
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
New file
@@ -0,0 +1,237 @@
package com.ruoyi.chargingPile.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.chargingPile.api.dto.PageChargingPileListDTO;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.query.BatchSetAccountingStrategy;
import com.ruoyi.chargingPile.api.query.PageChargingPileList;
import com.ruoyi.chargingPile.api.vo.UpdateChargingPileStatusVo;
import com.ruoyi.chargingPile.service.TChargingGunService;
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.log.enums.OperatorType;
import com.ruoyi.common.security.annotation.Logical;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
 * 充电桩 前端控制器
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Api(tags = "充电桩")
@RestController
@RequestMapping("/t-charging-pile")
public class TChargingPileController {
    private final TChargingPileService chargingPileService;
    private final TChargingGunService chargingGunService;
    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    public TChargingPileController(TChargingPileService chargingPileService, TChargingGunService chargingGunService) {
        this.chargingPileService = chargingPileService;
        this.chargingGunService = chargingGunService;
    }
    /**
     * 查询充电桩列表
     */
    @ApiOperation(tags = {"小程序-充电桩"},value = "通过站点id查询充电桩列表")
    @GetMapping(value = "/list")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "siteId", value = "站点id")
    })
    public AjaxResult<List<TChargingPile>> list(@RequestParam("siteId") Integer siteId) {
        return AjaxResult.ok(chargingPileService.list(Wrappers.lambdaQuery(TChargingPile.class)
                .eq(TChargingPile::getSiteId,siteId)));
    }
    /**
     * 查询充电桩列表
     */
    @ApiOperation(tags = {"通过充电桩id 查询充电枪列表"},value = "通过充电桩id 查询充电枪列表")
    @PostMapping(value = "/pileList")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pileId", value = "充电桩id")
    })
    public AjaxResult<List<TChargingGun>> pileList(@RequestParam("pileId") Integer pileId) {
        return AjaxResult.ok(chargingGunService.list(Wrappers.lambdaQuery(TChargingGun.class)
                .eq(TChargingGun::getChargingPileId,pileId)));
    }
    /**
     * 管理后台-通过站点id获取充电桩列表 不分页
     */
    @ApiOperation(value = "管理后台-通过站点id获取充电桩列表 不分页")
    @PostMapping(value = "/getChargingPileBySiteId")
    public R<List<TChargingPile>> getChargingPileBySiteId(@RequestParam("siteId") Integer siteId) {
        return R.ok(chargingPileService.list(Wrappers.lambdaQuery(TChargingPile.class)
                .eq(TChargingPile::getSiteId,siteId)));
    }
    @PostMapping(value = "/getChargingPileBySiteIds")
    public R<List<TChargingPile>> getChargingPileBySiteIds(@RequestParam("siteIds") List<Integer> siteIds) {
        return R.ok(chargingPileService.list(Wrappers.lambdaQuery(TChargingPile.class)
                .in(!siteIds.isEmpty(),TChargingPile::getSiteId,siteIds)));
    }
    @RequiresPermissions(value = {"/chargingPile", "/chargingGun"}, logical = Logical.OR)
    @ResponseBody
    @GetMapping("/pageChargingPileList")
    @ApiOperation(value = "获取充电桩列表数据", tags = {"管理后台-充电桩信息"})
    public AjaxResult<PageInfo<PageChargingPileListDTO>> pageChargingPileList(PageChargingPileList page){
        PageInfo<PageChargingPileListDTO> list = chargingPileService.pageChargingPileList(page);
        return AjaxResult.success(list);
    }
    @RequiresPermissions(value = {"/chargingPile/add"}, logical = Logical.OR)
    @ResponseBody
    @Log(title = "【充电桩信息】添加充电桩数据", businessType = BusinessType.INSERT,operatorType = OperatorType.MANAGE)
    @PostMapping("/addChargingPile")
    @ApiOperation(value = "添加充电桩数据", tags = {"管理后台-充电桩信息"})
    public AjaxResult addChargingPile(@RequestBody TChargingPile chargingPile){
        return chargingPileService.addChargingPile(chargingPile);
    }
    @RequiresPermissions(value = {"/chargingPile/select", "/chargingPile/update"}, logical = Logical.OR)
    @ResponseBody
    @GetMapping("/getChargingPile/{id}")
    @ApiOperation(value = "获取充电桩详情数据", tags = {"管理后台-充电桩信息"})
    public AjaxResult<TChargingPile> getChargingPile(@PathVariable Integer id){
        TChargingPile chargingPile = chargingPileService.getChargingPile(id);
        return AjaxResult.success(chargingPile);
    }
    @RequiresPermissions(value = {"/chargingPile/update"}, logical = Logical.OR)
    @ResponseBody
    @Log(title = "【充电桩信息】编辑充电桩数据", businessType = BusinessType.UPDATE,operatorType = OperatorType.MANAGE)
    @PostMapping("/editChargingPile")
    @ApiOperation(value = "编辑充电桩数据", tags = {"管理后台-充电桩信息"})
    public AjaxResult editChargingPile(@RequestBody TChargingPile chargingPile){
        return chargingPileService.editChargingPile(chargingPile);
    }
    @RequiresPermissions(value = {"/chargingPile/del", "/chargingPile/batch_del"}, logical = Logical.OR)
    @ResponseBody
    @DeleteMapping("/delChargingPile")
    @Log(title = "【充电桩信息】删除充电桩", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(value = "删除充电桩", tags = {"管理后台-充电桩信息"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "充电桩id", name = "id", dataTypeClass = Integer.class, required = true)
    })
    public AjaxResult delChargingPile(@RequestParam("id") Integer[] id){
        return chargingPileService.delChargingPile(id);
    }
    @RequiresPermissions(value = {"/chargingPile/accountingStrategy"}, logical = Logical.OR)
    @ResponseBody
    @Log(title = "【充电桩信息】批量设置计费策略", businessType = BusinessType.UPDATE,operatorType = OperatorType.MANAGE)
    @PostMapping("/batchSetAccountingStrategy")
    @ApiOperation(value = "批量设置计费策略", tags = {"管理后台-充电桩信息"})
    public AjaxResult batchSetAccountingStrategy(@RequestBody BatchSetAccountingStrategy setAccountingStrategy){
        chargingPileService.batchSetAccountingStrategy(setAccountingStrategy);
        return AjaxResult.success();
    }
    /**
     * 根据id获取充电桩信息
     * @param id
     * @return
     */
    @ResponseBody
    @PostMapping("/getChargingPileById/{id}")
    public R<TChargingPile> getChargingPileById(@PathVariable("id") Integer id){
        TChargingPile chargingPile = chargingPileService.getById(id);
        return R.ok(chargingPile);
    }
    /**
     * 更新充电桩状态
     */
    @ResponseBody
    @PostMapping("/updateChargingPileStatus")
    public void updateChargingPileStatus(@RequestBody UpdateChargingPileStatusVo vo){
        String pile_code = vo.getPile_code();
        String gun_code = vo.getGun_code();
        //0:正常,1:故障,2=插枪
        Integer status = vo.getStatus();
        Long time = (Long) redisTemplate.opsForHash().get("charging_gun_online", (pile_code + gun_code));
        //小于1分钟才处理数据,防止频繁查询数据
        if(null != time && (System.currentTimeMillis() - time) < 30000){
            return;
        }
        TChargingGun tChargingGun = chargingGunService.getOne(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getFullNumber, (pile_code + gun_code)).eq(TChargingGun::getDelFlag, 0));
        if(null != tChargingGun){
            redisTemplate.opsForHash().put("charging_gun_online", tChargingGun.getFullNumber(), System.currentTimeMillis());
            TChargingPile chargingPile = chargingPileService.getById(tChargingGun.getChargingPileId());
            //枪处于离线或者故障,返回状态为正常,则修改其状态
            if(0 == status && tChargingGun.getStatus() != 2){
                TChargingGun tChargingGun1 = new TChargingGun();
                tChargingGun1.setId(tChargingGun.getId());
                tChargingGun1.setStatus(2);
                chargingGunService.updateById(tChargingGun1);
                if(chargingPile.getStatus() != 1){
                    TChargingPile chargingPile1 = new TChargingPile();
                    chargingPile1.setId(chargingPile.getId());
                    chargingPile1.setStatus(1);
                    chargingPileService.updateById(chargingPile1);
                }
            }
            //枪处于正常,返回状态为故障,则修改其状态
            if(1 == status && tChargingGun.getStatus() != 1 && tChargingGun.getStatus() != 7){
                TChargingGun tChargingGun1 = new TChargingGun();
                tChargingGun1.setId(tChargingGun.getId());
                tChargingGun1.setStatus(7);
                chargingGunService.updateById(tChargingGun1);
                //桩处于正常,桩所属的枪都处于非正常,修改桩状态为异常
                List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, chargingPile.getId()).eq(TChargingGun::getDelFlag, 0));
                int size = list.stream().filter(s -> s.getStatus() == 1 || s.getStatus() == 7).collect(Collectors.toList()).size();
                if(chargingPile.getStatus() == 1 && list.size() == size){
                    TChargingPile chargingPile1 = new TChargingPile();
                    chargingPile1.setId(chargingPile.getId());
                    chargingPile1.setStatus(3);
                    chargingPileService.updateById(chargingPile1);
                }
            }
            if(2 == status){
            }
        }
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ResetPassword.java
New file
@@ -0,0 +1,18 @@
package com.ruoyi.chargingPile.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 15:56
 */
@Data
@ApiModel
public class ResetPassword {
    @ApiModelProperty(value = "合作商id", required = true)
    private Integer id;
    @ApiModelProperty(value = "新密码", required = true)
    private String password;
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/SiteDTO.java
New file
@@ -0,0 +1,18 @@
package com.ruoyi.chargingPile.dto;
import com.ruoyi.chargingPile.api.model.Site;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "站点信息DTO")
public class SiteDTO extends Site {
    @ApiModelProperty(value = "账号")
    private String account;
    @ApiModelProperty(value = "密码")
    private String password;
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/SiteMapper.java
New file
@@ -0,0 +1,66 @@
package com.ruoyi.chargingPile.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.query.GetSiteList;
import com.ruoyi.chargingPile.api.query.SiteDetailQuery;
import com.ruoyi.chargingPile.api.query.SiteQuery;
import com.ruoyi.chargingPile.api.vo.SiteDetailVO;
import com.ruoyi.chargingPile.api.vo.SiteVO;
import com.ruoyi.common.core.web.page.PageInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 19:49
 */
@Mapper
public interface SiteMapper extends BaseMapper<Site> {
    /**
     * 获取站点列表
     * @param pageInfo
     * @param siteList
     * @return
     */
    List<GetSiteListDTO> getSiteList(PageInfo<GetSiteListDTO> pageInfo, @Param("item") GetSiteList siteList, @Param("ids") Set<Integer> ids);
    /**
     * 获取站点分页列表
     * @return
     */
    List<SiteVO> pageList(@Param("query")SiteQuery query,@Param("pageInfo")PageInfo<SiteVO> pageInfo);
    /**
     * 获取站点详情
     * @param query
     * @return
     */
    SiteDetailVO getDetailById(@Param("query") SiteDetailQuery query);
    /**
     * 获取站点列表不分页 管理后台-停车场绑定
     * @return
     */
    List<Site> getSiteListParkLot(@Param("ids")Set<Integer> ids);
    /**
     * 获取站点列表不分页接口信息使用
     * @param ids
     * @return
     */
    List<Site> getSiteListGun(@Param("ids")Set<Integer> ids);
    /**
     * 获取站点列表不分页
     * @param query
     * @return
     */
    List<SiteVO> getMapSiteList(@Param("query")SiteQuery query);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TAccountingStrategyDetailMapper.java
New file
@@ -0,0 +1,29 @@
package com.ruoyi.chargingPile.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyDetailVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
 * 计费策略明细 Mapper 接口
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Mapper
public interface TAccountingStrategyDetailMapper extends BaseMapper<TAccountingStrategyDetail> {
    /**
     * 查询计费策略明细列表
     * @param strategyId
     * @return
     */
    List<TAccountingStrategyDetailVO> queryAccountingStrategyDetailByStrategyId(@Param("strategyId") Integer strategyId);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TAccountingStrategyMapper.java
New file
@@ -0,0 +1,39 @@
package com.ruoyi.chargingPile.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.chargingPile.api.query.TAccountingStrategyQuery;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyVO;
import com.ruoyi.common.core.web.page.PageInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
 * 计费策略 Mapper 接口
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Mapper
public interface TAccountingStrategyMapper extends BaseMapper<TAccountingStrategy> {
    /**
     * 查询计费策略分页列表
     * @param query
     * @param pageInfo
     * @return
     */
    List<TAccountingStrategyVO> pageList(@Param("query") TAccountingStrategyQuery query, @Param("pageInfo")PageInfo<TAccountingStrategyVO> pageInfo);
    List<TAccountingStrategyVO> pageList1(@Param("query") TAccountingStrategyQuery query, @Param("pageInfo")PageInfo<TAccountingStrategyVO> pageInfo);
    /**
     * 获取平台添加的计费策略
     * @return
     */
    List<TAccountingStrategyVO> getPlatformAccountingStrategy();
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TChargingGunMapper.java
New file
@@ -0,0 +1,49 @@
package com.ruoyi.chargingPile.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.query.TChargingGunQuery;
import com.ruoyi.chargingPile.api.vo.StatusModeStatisticsVO;
import com.ruoyi.chargingPile.api.vo.TChargingGunVO;
import com.ruoyi.common.core.web.page.PageInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
 * <p>
 * 充电枪 Mapper 接口
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Mapper
public interface TChargingGunMapper extends BaseMapper<TChargingGun> {
    /**
     * 查询充电枪分页列表
     * @param query
     * @param pageInfo
     * @return
     */
    List<TChargingGunVO> pageList(@Param("query") TChargingGunQuery query, @Param("pageInfo")PageInfo<TChargingGunVO> pageInfo, @Param("siteIds") Set<Integer> siteIds);
    /**
     * 统计充电枪状态
     * @param siteIds
     * @param chargeMode
     * @return
     */
    StatusModeStatisticsVO getStatusModeStatistics(@Param("siteIds")List<Integer> siteIds, @Param("chargeMode")Integer chargeMode);
    /**
     * 统计充电枪状态
     * @param siteIds
     * @return
     */
    List<Map<String, Object>> getModeStatistics(@Param("siteIds")List<Integer> siteIds);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/mapper/TChargingPileMapper.java
New file
@@ -0,0 +1,50 @@
package com.ruoyi.chargingPile.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.chargingPile.api.dto.PageChargingPileListDTO;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.query.PageChargingPileList;
import com.ruoyi.chargingPile.api.vo.TChargingPileVO;
import com.ruoyi.common.core.web.page.PageInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
 * <p>
 * 充电桩 Mapper 接口
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Mapper
public interface TChargingPileMapper extends BaseMapper<TChargingPile> {
    /**
     * 获取充电桩列表数据
     * @param page
     * @return
     */
    List<PageChargingPileListDTO> pageChargingPileList(PageInfo<PageChargingPileListDTO> pageInfo, @Param("item") PageChargingPileList page, @Param("siteIds") Set<Integer> siteIds);
    /**
     * 获取充电桩详情
     * @param id
     * @return
     */
    TChargingPile getChargingPile(@Param("id") Integer id);
    /**
     * 获取站点下充电桩及充电枪列表
     * @param siteId
     * @return
     */
    List<TChargingPileVO> getChargingGunList(@Param("siteId")Integer siteId);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/ISiteService.java
New file
@@ -0,0 +1,82 @@
package com.ruoyi.chargingPile.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.query.GetSiteList;
import com.ruoyi.chargingPile.api.query.SiteDetailQuery;
import com.ruoyi.chargingPile.api.query.SiteQuery;
import com.ruoyi.chargingPile.api.vo.SiteDetailVO;
import com.ruoyi.chargingPile.api.vo.SiteVO;
import com.ruoyi.chargingPile.dto.SiteDTO;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 19:54
 */
public interface ISiteService extends IService<Site> {
    /**
     * 获取站点管理列表
     * @param siteList
     * @return
     */
    PageInfo<GetSiteListDTO> getSiteList(GetSiteList siteList);
    PageInfo<GetSiteListDTO> getSiteList1(Long userId);
    /**
     * 添加站点信息
     * @param dto
     * @return
     */
    AjaxResult addSite(SiteDTO dto);
    /**
     * 编辑站点
     * @param site
     * @return
     */
    AjaxResult editSite(Site site);
    /**
     * 删除站点
     * @param id
     * @return
     */
    AjaxResult delSite(Integer[] id);
    /**
     * 设置站点计费策略
     * @param id 站点id
     * @param accountingStrategyId 计费策略id
     */
    void setAccountingStrategy(Integer id, Integer accountingStrategyId);
    /**
     * 获取站点分页列表
     * @param query
     * @return
     */
    PageInfo<SiteVO> pageList(SiteQuery query,Integer isLogin);
    /**
     * 获取站点详情
     * @param query
     * @return
     */
    SiteDetailVO getDetailById(SiteDetailQuery query);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TAccountingStrategyDetailService.java
New file
@@ -0,0 +1,67 @@
package com.ruoyi.chargingPile.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import com.ruoyi.chargingPile.api.vo.StrategyPriceVO;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyDetailVO;
import java.util.List;
/**
 * <p>
 * 计费策略明细 服务类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
public interface TAccountingStrategyDetailService extends IService<TAccountingStrategyDetail> {
    /**
     * 查询计费策略明细列表
     * @param strategyId
     * @return
     */
    List<TAccountingStrategyDetailVO> queryAccountingStrategyDetailByStrategyId(Integer strategyId);
    /**
     * 查询计费策略明细列表---后台
     * @param strategyId
     * @return
     */
    List<TAccountingStrategyDetailVO> queryMangementAccountingStrategyDetailByStrategyId(Integer strategyId);
    /**
     * 通过站点id查询当前时间段计费策略展示
     * @param siteId
     * @return
     */
    List<TAccountingStrategyDetailVO> queryStrategyBySiteIdAndTime(Integer siteId);
    /**
     * 价格说明金额返回,会员开通金额说明
     * @param siteId
     * @return
     */
    StrategyPriceVO queryPrice(Integer siteId);
    /**
     * 判断是否满足24小时策略
     * @param accountingStrategyDetails
     * @return
     */
    Boolean isStrategy24Hour(List<TAccountingStrategyDetail> accountingStrategyDetails);
    /**
     * 判断同阶段是否价格不一致
     * @param accountingStrategyDetails
     * @return
     */
    Boolean isStrategyPriceConsistent(List<TAccountingStrategyDetail> accountingStrategyDetails);
    /**
     * 通过枪id查询当前时间段计费策略展示
     * @param gunId
     * @return
     */
    List<TAccountingStrategyDetailVO> queryStrategyByGunIdAndTime(Integer gunId);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TAccountingStrategyService.java
New file
@@ -0,0 +1,34 @@
package com.ruoyi.chargingPile.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.chargingPile.api.query.TAccountingStrategyQuery;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyVO;
import com.ruoyi.common.core.web.page.PageInfo;
import java.util.List;
/**
 * <p>
 * 计费策略 服务类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
public interface TAccountingStrategyService extends IService<TAccountingStrategy> {
    /**
     * 查询计费策略分页列表
     * @param query
     * @return
     */
    PageInfo<TAccountingStrategyVO> pageList(TAccountingStrategyQuery query);
    PageInfo<TAccountingStrategyVO> pageList1(TAccountingStrategyQuery query);
    /**
     * 获取平台添加的计费策略
     * @return
     */
    List<TAccountingStrategyVO> getPlatformAccountingStrategy();
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java
New file
@@ -0,0 +1,61 @@
package com.ruoyi.chargingPile.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.chargingPile.api.dto.TChargingGunDTO;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.query.TChargingGunQuery;
import com.ruoyi.chargingPile.api.vo.ChargingGunCountVO;
import com.ruoyi.chargingPile.api.vo.GunStatusStatisticsVO;
import com.ruoyi.chargingPile.api.vo.TChargingGunVO;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import java.util.List;
import java.util.Map;
/**
 * <p>
 * 充电枪 服务类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
public interface TChargingGunService extends IService<TChargingGun> {
    /**
     * 查询充电枪分页列表
     * @param query
     * @return
     */
    PageInfo<TChargingGunVO> pageList(TChargingGunQuery query);
    /**
     * 添加充电枪
     * @param dto
     * @return
     */
    AjaxResult add(TChargingGunDTO dto);
    /**
     * 编辑充电枪
     * @param dto
     * @return
     */
    AjaxResult update(TChargingGunDTO dto);
    /**
     * 获取站点下充电枪数量统计
     * @param siteId
     * @return
     */
    Map<String, ChargingGunCountVO> getChargingGunCount(Integer siteId);
    /**
     * 设备状态统计
     * @param siteIds
     * @return
     */
    GunStatusStatisticsVO gunStatusStatistics(List<Integer> siteIds);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java
New file
@@ -0,0 +1,85 @@
package com.ruoyi.chargingPile.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.chargingPile.api.dto.PageChargingPileListDTO;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.query.BatchSetAccountingStrategy;
import com.ruoyi.chargingPile.api.query.PageChargingPileList;
import com.ruoyi.chargingPile.api.vo.TChargingPileVO;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import java.util.List;
/**
 * <p>
 * 充电桩 服务类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
public interface TChargingPileService extends IService<TChargingPile> {
    /**
     * 获取充电桩列表
     * @param page
     * @return
     */
    PageInfo<PageChargingPileListDTO> pageChargingPileList(PageChargingPileList page);
    /**
     * 添加充电桩
     * @param chargingPile
     * @return
     */
    AjaxResult addChargingPile(TChargingPile chargingPile);
    /**
     * 获取充电桩详情
     * @param id 充电桩id
     * @return
     */
    TChargingPile getChargingPile(Integer id);
    /**
     * 编辑充电桩
     * @param chargingPile
     * @return
     */
    AjaxResult editChargingPile(TChargingPile chargingPile);
    /**
     * 删除充电桩
     * @param id
     * @return
     */
    AjaxResult delChargingPile(Integer[] id);
    /**
     * 批量设置计费策略
     * @param setAccountingStrategy
     */
    void batchSetAccountingStrategy(BatchSetAccountingStrategy setAccountingStrategy);
    /**
     * 获取站点下充电桩及充电枪列表
     * @param siteId
     * @param type
     * @return
     */
    List<TChargingPileVO> getChargingGunList(Integer siteId,Integer type);
    /**
     * 定时任务修改充电桩状态
     */
    void updateStatus();
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/SiteServiceImpl.java
New file
@@ -0,0 +1,291 @@
package com.ruoyi.chargingPile.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.feignClient.AppUserClient;
import com.ruoyi.chargingPile.api.dto.GetSiteListDTO;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.query.GetSiteList;
import com.ruoyi.chargingPile.api.query.SiteDetailQuery;
import com.ruoyi.chargingPile.api.query.SiteQuery;
import com.ruoyi.chargingPile.api.vo.SiteDetailVO;
import com.ruoyi.chargingPile.api.vo.SiteVO;
import com.ruoyi.chargingPile.dto.SiteDTO;
import com.ruoyi.chargingPile.mapper.SiteMapper;
import com.ruoyi.chargingPile.service.ISiteService;
import com.ruoyi.chargingPile.service.TAccountingStrategyDetailService;
import com.ruoyi.chargingPile.service.TChargingGunService;
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import com.ruoyi.system.api.feignClient.SysUserRoleClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
 * @author zhibing.pu
 * @Date 2024/8/7 19:54
 */
@Service
public class SiteServiceImpl extends ServiceImpl<SiteMapper, Site> implements ISiteService {
    @Resource
    private TChargingGunService chargingGunService;
    @Resource
    private TChargingPileService chargingPileService;
    @Resource
    private SysUserClient sysUserClient;
    /**
     * 获取站点管理列表数据
     * @param siteList
     * @return
     */
    @Override
    public PageInfo<GetSiteListDTO> getSiteList(GetSiteList siteList) {
        Set<Integer> ids = null;
        PageInfo<GetSiteListDTO> pageInfo = new PageInfo<>(siteList.getPageCurr(), siteList.getPageSize());
        List<GetSiteListDTO> list = this.baseMapper.getSiteList(pageInfo, siteList, ids);
        return pageInfo.setRecords(list);
    }
    @Override
    public PageInfo<GetSiteListDTO> getSiteList1(Long userId) {
        GetSiteList siteList = new GetSiteList();
        siteList.setPageCurr(1);
        siteList.setPageSize(9999);
        Set<Integer> ids = null;
        //校验合作商权限
        PageInfo<GetSiteListDTO> pageInfo = new PageInfo<>(siteList.getPageCurr(), siteList.getPageSize());
        List<GetSiteListDTO> list = this.baseMapper.getSiteList(pageInfo, siteList, ids);
        return pageInfo.setRecords(list);
    }
    /**
     * 添加站点信息
     * @param dto
     * @return
     */
    @Override
    public AjaxResult addSite(SiteDTO dto) {
        AjaxResult ajaxResult = addSiteVerify(dto);
        if(ajaxResult.isError()){
            return ajaxResult;
        }
        Site one = this.getOne(new LambdaQueryWrapper<Site>().eq(Site::getCode, dto.getCode()).eq(Site::getDelFlag, 0));
        if(null != one){
            return AjaxResult.error("站点编号重复");
        }
        this.save(dto);
        // 添加登录账号
        SysUser user = new SysUser();
        user.setPhonenumber(dto.getPhone());
        user.setUserName(dto.getAccount());
        user.setNickName(dto.getName());
        user.setPassword(dto.getPassword());
        user.setStatus("0");
        user.setDelFlag("0");
        user.setRoleId(2L);
        R<Long> r = sysUserClient.addSysUser(user);
        if(200 != r.getCode()){
            throw new RuntimeException(r.getMsg());
        }
        return AjaxResult.success();
    }
    /**
     * 编辑站点
     * @param site
     * @return
     */
    @Override
    public AjaxResult editSite(Site site) {
        AjaxResult ajaxResult = addSiteVerify(site);
        if(ajaxResult.isError()){
            return ajaxResult;
        }
        Site one = this.getOne(new LambdaQueryWrapper<Site>().eq(Site::getCode, site.getCode()).eq(Site::getDelFlag, 0));
        if(null != one && !one.getCode().equals(site.getCode())){
            return AjaxResult.error("站点编号重复");
        }
        this.updateById(site);
        return AjaxResult.success();
    }
    /**
     * 校验必填项
     * @param site
     * @return
     */
    AjaxResult addSiteVerify(Site site){
        if(StringUtils.isEmpty(site.getCode())){
            return AjaxResult.error("站点编号不能为空");
        }
        if(StringUtils.isEmpty(site.getName())){
            return AjaxResult.error("站点名称不能为空");
        }
        if(null == site.getSiteType()){
            return AjaxResult.error("站点类型不能为空");
        }
        if(null == site.getBusinessCategory()){
            return AjaxResult.error("经营类别不能为空");
        }
        if(null == site.getStatus()){
            return AjaxResult.error("站点状态不能为空");
        }
        if(null == site.getConstructionSite()){
            return AjaxResult.error("建设场所不能为空");
        }
        if(StringUtils.isEmpty(site.getProvince()) || StringUtils.isEmpty(site.getProvinceCode()) ||
                StringUtils.isEmpty(site.getCity()) || StringUtils.isEmpty(site.getCityCode()) ||
                StringUtils.isEmpty(site.getDistricts()) || StringUtils.isEmpty(site.getDistrictsCode())){
            return AjaxResult.error("所在区域不能为空");
        }
        if(StringUtils.isEmpty(site.getAddress())){
            return AjaxResult.error("详细地址不能为空");
        }
//        if(StringUtils.isEmpty(site.getLon()) || StringUtils.isEmpty(site.getLat())){
//            return AjaxResult.error("地图位置不能为空");
//        }
//        if(StringUtils.isEmpty(site.getPhone())){
//            return AjaxResult.error("站点电话不能为空");
//        }
        if(StringUtils.isEmpty(site.getServicePhone())){
            return AjaxResult.error("服务电话不能为空");
        }
        if(null == site.getParkingSpace()){
            return AjaxResult.error("车位数量不能为空");
        }
        if(null == site.getSort()){
            return AjaxResult.error("排序不能为空");
        }
//        if(StringUtils.isEmpty(site.getAreaCodeCountryside())){
//            return AjaxResult.error("充换电站所在县以下行政区划代码不能为空");
//        }
//        if(null == site.getStationClassification()){
//            return AjaxResult.error("请选择站点分类");
//        }
//        if(null == site.getGeneralApplicationType()){
//            return AjaxResult.error("请选择通用类型");
//        }
//        if(null == site.getParkType()){
//            return AjaxResult.error("请选择停车费类型");
//        }
//        if(null == site.getRoundTheClock()){
//            return AjaxResult.error("请选择是否7*24h营业");
//        }
//        if (site.getStationClassification()!=1&& (!org.springframework.util.StringUtils.hasLength(site.getSwapMatchCars()))){
//            return AjaxResult.error("服务车型描述不能为空");
//        }
//        if(null == site.getElectricityType()){
//            return AjaxResult.error("请选择电费类型");
//        }
//        if(null == site.getBusinessExpandType()){
//            return AjaxResult.error("请选择报装类型");
//        }
//        if(null == site.getCapacity()){
//            return AjaxResult.error("报装电源容量不能为空");
//        }
//        if(null == site.getRatedPower()){
//            return AjaxResult.error("站点额定总功率不能为空");
//        }
//        if(StringUtils.isEmpty(site.getOfficialRunTime())){
//            return AjaxResult.error("请选择正式投运时间");
//        }
//        if(null == site.getPeriodFee()){
//            return AjaxResult.error("请选择峰谷时分");
//        }
//        if(null == site.getVideoMonitor()){
//            return AjaxResult.error("请选择视频监控配套情况");
//        }
//        if(StringUtils.isEmpty(site.getEquipmentOwnerName())){
//            return AjaxResult.error("设备所属方名称不能为空");
//        }
//        if(null == site.getSupplyType()){
//            return AjaxResult.error("请选择供电类型");
//        }
//        if(site.getSupplyType()==1){
//            if (StringUtils.isEmpty(site.getResidentNo())){
//                return AjaxResult.error("供电局用户编号不能为空");
//            }
//        }
        return AjaxResult.success();
    }
    /**
     * 删除站点
     * @param ids 站点id
     * @return
     */
    @Override
    public AjaxResult delSite(Integer[] ids) {
        //查询是否有关联数据
        //充电桩
        long count1 = chargingPileService.count(new LambdaQueryWrapper<TChargingPile>().in(TChargingPile::getSiteId, Arrays.asList(ids))
                .eq(TChargingPile::getDelFlag, 0));
        if(count1 > 0){
            return AjaxResult.error("该站点已添加充电桩,不可删除。");
        }
        for (Integer id : ids) {
            Site site = this.getById(id);
            this.removeById(site);
        }
        return AjaxResult.success();
    }
    @Override
    public PageInfo<SiteVO> pageList(SiteQuery query,Integer isLogin) {
        PageInfo<SiteVO> pageInfo = new PageInfo<>(query.getPageCurr(),query.getPageSize());
        List<SiteVO> list = this.baseMapper.pageList(query,pageInfo);
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public SiteDetailVO getDetailById(SiteDetailQuery query) {
        return this.baseMapper.getDetailById(query);
    }
    /**
     * 设置站点计费策略
     * @param id 站点id
     * @param accountingStrategyId 计费策略id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setAccountingStrategy(Integer id, Integer accountingStrategyId) {
        Site site = this.getById(id);
        site.setAccountingStrategyId(accountingStrategyId);
        this.updateById(site);
        List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().in(TChargingGun::getSiteId, id).eq(TChargingGun::getDelFlag, 0));
        for (TChargingGun tChargingGun : list) {
            TChargingGun tChargingGun1 = new TChargingGun();
            tChargingGun1.setId(tChargingGun.getId());
            tChargingGun1.setAccountingStrategyId(accountingStrategyId);
            chargingGunService.updateById(tChargingGun1);
        }
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TAccountingStrategyDetailServiceImpl.java
New file
@@ -0,0 +1,187 @@
package com.ruoyi.chargingPile.service.impl;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.feignClient.AppUserClient;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.vo.StrategyPriceVO;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyDetailVO;
import com.ruoyi.chargingPile.mapper.TAccountingStrategyDetailMapper;
import com.ruoyi.chargingPile.mapper.TAccountingStrategyMapper;
import com.ruoyi.chargingPile.service.ISiteService;
import com.ruoyi.chargingPile.service.TAccountingStrategyDetailService;
import com.ruoyi.chargingPile.service.TChargingGunService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.security.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
 * 计费策略明细 服务实现类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Service
public class TAccountingStrategyDetailServiceImpl extends ServiceImpl<TAccountingStrategyDetailMapper, TAccountingStrategyDetail> implements TAccountingStrategyDetailService {
    @Autowired
    private TAccountingStrategyMapper accountingStrategyMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private ISiteService siteService;
    @Autowired
    private TChargingGunService chargingGunService;
    @Override
    public List<TAccountingStrategyDetailVO> queryAccountingStrategyDetailByStrategyId(Integer strategyId) {
        List<TAccountingStrategyDetailVO> tAccountingStrategyDetailVOS = this.baseMapper.queryAccountingStrategyDetailByStrategyId(strategyId);
        return tAccountingStrategyDetailVOS;
    }
    @Override
    public List<TAccountingStrategyDetailVO> queryMangementAccountingStrategyDetailByStrategyId(Integer strategyId) {
        return this.baseMapper.queryAccountingStrategyDetailByStrategyId(strategyId);
    }
    @Override
    public List<TAccountingStrategyDetailVO> queryStrategyBySiteIdAndTime(Integer siteId) {
        Site site = siteService.getById(siteId);
        TAccountingStrategy accountingStrategy = accountingStrategyMapper.selectById(site.getAccountingStrategyId());
        if(Objects.isNull(accountingStrategy)){
            throw new ServiceException("未查询到计费策略");
        }
        List<TAccountingStrategyDetailVO> list = this.queryAccountingStrategyDetailByStrategyId(accountingStrategy.getId());
        list.stream().filter(item -> "00:00".equals(item.getEndTime())).forEach(item -> item.setEndTime("23:59:59"));
        TAccountingStrategyDetailVO accountingStrategyDetailVO;
        TAccountingStrategyDetailVO accountingStrategyDetailNext;
        // 获取当前时间段的计费策略明细
        accountingStrategyDetailVO = list.stream().filter(detail -> DateUtils.string2LocalTime(detail.getStartTime() + ":00").compareTo(LocalTime.now()) <= 0
                        && DateUtils.string2LocalTime(detail.getEndTime() + ("23:59:59".equals(detail.getEndTime())?"":":00")).compareTo(LocalTime.now()) > 0)
                .findFirst().orElseThrow(() -> new ServiceException("当前时间段未查询到计费策略明细"));
        // 获取后一次的计费策略明细
        accountingStrategyDetailVO.setEndTime("23:59:59".equals(accountingStrategyDetailVO.getEndTime())? "00:00":accountingStrategyDetailVO.getEndTime());
        accountingStrategyDetailNext = list.stream().filter(detail -> detail.getStartTime().compareTo(accountingStrategyDetailVO.getEndTime()) == 0)
                .findFirst().orElseThrow(() -> new ServiceException("未查询到下一时间段的计费策略明细"));
        accountingStrategyDetailVO.setTotalPrice(accountingStrategyDetailVO.getElectrovalence().add(accountingStrategyDetailVO.getServiceCharge()));
        accountingStrategyDetailNext.setTotalPrice(accountingStrategyDetailNext.getElectrovalence().add(accountingStrategyDetailNext.getServiceCharge()));
        list = new ArrayList<>();
        list.add(accountingStrategyDetailVO);
        list.add(accountingStrategyDetailNext);
        return list;
    }
    @Override
    public StrategyPriceVO queryPrice(Integer siteId) {
        Site site = siteService.getById(siteId);
        TAccountingStrategy accountingStrategy = accountingStrategyMapper.selectById(site.getAccountingStrategyId());
        if(Objects.isNull(accountingStrategy)){
            throw new ServiceException("未查询到计费策略");
        }
        StrategyPriceVO strategyPriceVO = new StrategyPriceVO();
        List<TAccountingStrategyDetailVO> list = this.queryAccountingStrategyDetailByStrategyId(accountingStrategy.getId());
        list.stream().filter(item -> "24:00".equals(item.getEndTime())).forEach(item -> item.setEndTime("23:59:59"));
        // 获取当前时间段的计费策略明细
        TAccountingStrategyDetailVO accountingStrategyDetailVO = list.stream().filter(detail -> DateUtils.string2LocalTime(detail.getStartTime() + ":00").compareTo(LocalTime.now()) <= 0
                        && DateUtils.string2LocalTime(detail.getEndTime() + ("23:59:59".equals(detail.getEndTime())?"":":00")).compareTo(LocalTime.now()) > 0)
                .findFirst().orElseThrow(() -> new ServiceException("当前时间段未查询到计费策略明细"));
//        strategyPriceVO.setDiscountAmount(accountingStrategyDetailVO.getElectrovalence().add(accountingStrategyDetailVO.getServiceCharge())
//                .subtract(accountingStrategyDetailVO.getServiceCharge().multiply(accountingStrategy.getDiscount())).setScale(2, BigDecimal.ROUND_HALF_UP));
        if(Objects.isNull(accountingStrategy.getDiscount())){
            strategyPriceVO.setDiscountAmount(BigDecimal.ZERO);
        }else {
            strategyPriceVO.setDiscountAmount(accountingStrategyDetailVO.getServiceCharge()
                    .subtract(accountingStrategyDetailVO.getServiceCharge().multiply(accountingStrategy.getDiscount())).setScale(2, BigDecimal.ROUND_HALF_UP));
        }
        // 模板折扣
        strategyPriceVO.setDiscount(accountingStrategy.getDiscount());
        return strategyPriceVO;
    }
    @Override
    public Boolean isStrategy24Hour(List<TAccountingStrategyDetail> accountingStrategyDetails) {
        List<TAccountingStrategyDetail> sortedDetails = accountingStrategyDetails.stream()
                .sorted(Comparator.comparing(TAccountingStrategyDetail::getStartTime))
                .collect(Collectors.toList());
        boolean isFirstElementValid = sortedDetails.isEmpty() || !sortedDetails.get(0).getStartTime().equals(sortedDetails.get(sortedDetails.size() - 1).getEndTime());
        boolean isTimeContinuous = sortedDetails.stream()
                .skip(1)
                .allMatch(detail -> detail.getStartTime().equals(sortedDetails.get(sortedDetails.indexOf(detail) - 1).getEndTime()));
        return isFirstElementValid || !isTimeContinuous;
    }
    @Override
    public Boolean isStrategyPriceConsistent(List<TAccountingStrategyDetail> accountingStrategyDetails) {
        Map<Integer, BigDecimal> phaseToServiceFee = new HashMap<>();
        Map<Integer, BigDecimal> phaseToCostServiceFee = new HashMap<>();
        for (TAccountingStrategyDetail detail : accountingStrategyDetails) {
            Integer type = detail.getType();
            BigDecimal serviceFee = detail.getServiceCharge();
            BigDecimal costServiceCharge = detail.getCostServiceCharge();
            if (phaseToServiceFee.containsKey(type)) {
                BigDecimal existingFee = phaseToServiceFee.get(type);
                BigDecimal existingCostServiceCharge = phaseToCostServiceFee.get(type);
                if (existingFee.compareTo(serviceFee) != 0) {
                    return false; // 发现不一致的服务费
                }
                if (existingCostServiceCharge.compareTo(costServiceCharge) != 0) {
                    return false; // 发现不一致的原价服务费
                }
            } else {
                phaseToServiceFee.put(type, serviceFee);
                phaseToCostServiceFee.put(type, costServiceCharge);
            }
        }
        return true; // 所有相同阶段的服务费一致
    }
    @Override
    public List<TAccountingStrategyDetailVO> queryStrategyByGunIdAndTime(Integer gunId) {
        TChargingGun chargingGun = chargingGunService.getById(gunId);
        TAccountingStrategy accountingStrategy = accountingStrategyMapper.selectById(chargingGun.getAccountingStrategyId());
        if(Objects.isNull(accountingStrategy)){
            Site site = siteService.getById(chargingGun.getSiteId());
            accountingStrategy = accountingStrategyMapper.selectById(site.getAccountingStrategyId());
            if(Objects.isNull(accountingStrategy)){
                throw new ServiceException("未查询到计费策略");
            }
        }
        List<TAccountingStrategyDetailVO> list = this.queryAccountingStrategyDetailByStrategyId(accountingStrategy.getId());
        list.stream().filter(item -> "00:00".equals(item.getEndTime())).forEach(item -> item.setEndTime("23:59:59"));
        TAccountingStrategyDetailVO accountingStrategyDetailVO;
        TAccountingStrategyDetailVO accountingStrategyDetailNext;
        // 获取当前时间段的计费策略明细
        accountingStrategyDetailVO = list.stream().filter(detail -> DateUtils.string2LocalTime(detail.getStartTime() + ":00").compareTo(LocalTime.now()) <= 0
                        && DateUtils.string2LocalTime(detail.getEndTime() + ("23:59:59".equals(detail.getEndTime())?"":":00")).compareTo(LocalTime.now()) > 0)
                .findFirst().orElseThrow(() -> new ServiceException("当前时间段未查询到计费策略明细"));
        // 获取后一次的计费策略明细
        accountingStrategyDetailVO.setEndTime("23:59:59".equals(accountingStrategyDetailVO.getEndTime())? "00:00":accountingStrategyDetailVO.getEndTime());
        accountingStrategyDetailNext = list.stream().filter(detail -> detail.getStartTime().compareTo(accountingStrategyDetailVO.getEndTime()) == 0)
                .findFirst().orElseThrow(() -> new ServiceException("未查询到下一时间段的计费策略明细"));
        accountingStrategyDetailVO.setTotalPrice(accountingStrategyDetailVO.getElectrovalence().add(accountingStrategyDetailVO.getServiceCharge()));
        accountingStrategyDetailNext.setTotalPrice(accountingStrategyDetailNext.getElectrovalence().add(accountingStrategyDetailNext.getServiceCharge()));
        list = new ArrayList<>();
        list.add(accountingStrategyDetailVO);
        list.add(accountingStrategyDetailNext);
        return list;
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TAccountingStrategyServiceImpl.java
New file
@@ -0,0 +1,102 @@
package com.ruoyi.chargingPile.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.chargingPile.api.model.TAccountingStrategy;
import com.ruoyi.chargingPile.api.query.TAccountingStrategyQuery;
import com.ruoyi.chargingPile.api.vo.TAccountingStrategyVO;
import com.ruoyi.chargingPile.mapper.TAccountingStrategyMapper;
import com.ruoyi.chargingPile.service.TAccountingStrategyService;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
 * 计费策略 服务实现类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Service
public class TAccountingStrategyServiceImpl extends ServiceImpl<TAccountingStrategyMapper, TAccountingStrategy> implements TAccountingStrategyService {
    @Resource
    private SysUserClient sysUserClient;
    @Override
    public PageInfo<TAccountingStrategyVO> pageList(TAccountingStrategyQuery query) {
        PageInfo<TAccountingStrategyVO> pageInfo = new PageInfo<>(query.getPageCurr(),query.getPageSize());
        List<TAccountingStrategyVO> list = this.baseMapper.pageList(query,pageInfo);
        List<Integer> parentIds = list.stream().map(TAccountingStrategyVO::getId).collect(Collectors.toList());
        List<TAccountingStrategy> list1 = this.list(Wrappers.lambdaQuery(TAccountingStrategy.class)
                .in(!parentIds.isEmpty(),TAccountingStrategy::getParentId, parentIds)
                .in(TAccountingStrategy::getAuditStatus, Arrays.asList(1,2)));
        for (TAccountingStrategyVO tAccountingStrategyVO : list) {
            SysUser data = sysUserClient.getSysUser(tAccountingStrategyVO.getUserId()).getData();
            tAccountingStrategyVO.setUserName(data.getNickName());
            if (tAccountingStrategyVO.getFirstUserId()!=null){
                SysUser first = sysUserClient.getSysUser(tAccountingStrategyVO.getFirstUserId()).getData();
                tAccountingStrategyVO.setFirstUserName(first==null?null:first.getNickName());
            }
            if (tAccountingStrategyVO.getTwoUserId()!=null){
                SysUser two = sysUserClient.getSysUser(tAccountingStrategyVO.getTwoUserId()).getData();
                tAccountingStrategyVO.setTwoUserName(two==null?null:two.getNickName());
            }
            // 匹配编辑后的未审核的
            List<TAccountingStrategy> accountingStrategies = list1.stream().filter(e -> e.getParentId().equals(tAccountingStrategyVO.getId()))
                    .sorted(Comparator.comparing(TAccountingStrategy::getCreateTime).reversed()).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(accountingStrategies)){
                TAccountingStrategy tAccountingStrategy = accountingStrategies.get(0);
                if(tAccountingStrategyVO.getAuditStatus() == 4){
                    BeanUtils.copyProperties(tAccountingStrategy,tAccountingStrategyVO);
                }else {
                    tAccountingStrategyVO.setAuditStatus(tAccountingStrategy.getAuditStatus());
                }
            }
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public PageInfo<TAccountingStrategyVO> pageList1(TAccountingStrategyQuery query) {
        PageInfo<TAccountingStrategyVO> pageInfo = new PageInfo<>(query.getPageCurr(),query.getPageSize());
        List<TAccountingStrategyVO> list = this.baseMapper.pageList1(query,pageInfo);
        List<Integer> parentIds = list.stream().map(TAccountingStrategyVO::getId).collect(Collectors.toList());
        for (TAccountingStrategyVO tAccountingStrategyVO : list) {
            SysUser data = sysUserClient.getSysUser(tAccountingStrategyVO.getUserId()).getData();
            tAccountingStrategyVO.setUserName(data.getNickName());
            if (tAccountingStrategyVO.getFirstUserId()!=null){
                SysUser first = sysUserClient.getSysUser(tAccountingStrategyVO.getFirstUserId()).getData();
                tAccountingStrategyVO.setFirstUserName(first==null?null:first.getNickName());
            }
            if (tAccountingStrategyVO.getTwoUserId()!=null){
                SysUser two = sysUserClient.getSysUser(tAccountingStrategyVO.getTwoUserId()).getData();
                tAccountingStrategyVO.setTwoUserName(two==null?null:two.getNickName());
            }
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
    /**
     * 获取平台添加的计费策略
     * @return
     */
    @Override
    public List<TAccountingStrategyVO> getPlatformAccountingStrategy() {
        return this.baseMapper.getPlatformAccountingStrategy();
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java
New file
@@ -0,0 +1,312 @@
package com.ruoyi.chargingPile.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.chargingPile.api.dto.TChargingGunDTO;
import com.ruoyi.chargingPile.api.feignClient.SiteClient;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.query.TChargingGunQuery;
import com.ruoyi.chargingPile.api.vo.*;
import com.ruoyi.chargingPile.mapper.SiteMapper;
import com.ruoyi.chargingPile.mapper.TChargingGunMapper;
import com.ruoyi.chargingPile.service.TChargingGunService;
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.common.core.enums.status.ChargingGunModeEnum;
import com.ruoyi.common.core.enums.status.ChargingGunStatusEnum;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import com.ruoyi.system.api.feignClient.SysUserRoleClient;
import com.ruoyi.system.api.model.SysUserRoleVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
 * 充电枪 服务实现类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Service
public class TChargingGunServiceImpl extends ServiceImpl<TChargingGunMapper, TChargingGun> implements TChargingGunService {
    @Resource
    private SysUserClient sysUserClient;
    @Autowired
    private TChargingPileService chargingPileService;
    @Resource
    private SysUserRoleClient sysUserRoleClient;
    @Resource
    private SiteClient siteClient;
    @Resource
    private TokenService tokenService;
    @Override
    public PageInfo<TChargingGunVO> pageList(TChargingGunQuery query) {
        Set<Integer> siteIds = null;
        PageInfo<TChargingGunVO> pageInfo = new PageInfo<>(query.getPageCurr(),query.getPageSize());
        List<TChargingGunVO> list = this.baseMapper.pageList(query,pageInfo, siteIds);
        for (TChargingGunVO tChargingGunVO : list) {
            if(null == tChargingGunVO.getAccountingStrategyId()){
                List<Site> data = siteClient.getSiteByIds(Arrays.asList(tChargingGunVO.getSiteId())).getData();
                if(data.size() > 0){
                    Site site = data.get(0);
                    tChargingGunVO.setAccountingStrategyId(site.getAccountingStrategyId());
                }
            }
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
@Autowired
private SiteMapper siteMapper;
    /**
     * 添加充电枪
     * @param dto
     * @return
     */
    @Override
    public AjaxResult add(TChargingGunDTO dto) {
        AjaxResult ajaxResult = addVerify(dto);
        if(ajaxResult.isError()){
            return ajaxResult;
        }
        long count = this.count(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getCode, dto.getCode())
                .eq(TChargingGun::getDelFlag, 0).eq(TChargingGun::getChargingPileId, dto.getChargingPileId()));
        if(count > 0){
            return AjaxResult.error("接口编码已存在");
        }
        TChargingPile chargingPile = chargingPileService.getById(dto.getChargingPileId());
        dto.setFullNumber(chargingPile.getCode() + dto.getCode());
        this.save(dto);
        // 推送充换电站信息
        return AjaxResult.success();
    }
    /**
     * 编辑充电枪
     * @param dto
     * @return
     */
    @Override
    public AjaxResult update(TChargingGunDTO dto) {
        TChargingGun chargingGun = this.getById(dto.getId());
        if(Arrays.asList(3,4,5,6).contains(chargingGun.getStatus())){
            return AjaxResult.error("接口占用中,无法编辑!");
        }
        AjaxResult ajaxResult = addVerify(dto);
        if(ajaxResult.isError()){
            return ajaxResult;
        }
        TChargingGun one = this.getOne(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getCode, dto.getCode())
                .eq(TChargingGun::getDelFlag, 0).eq(TChargingGun::getChargingPileId, dto.getChargingPileId()));
        if(null != one && !dto.getId().equals(one.getId())){
            return AjaxResult.error("接口编码已存在");
        }
        TChargingPile chargingPile = chargingPileService.getById(dto.getChargingPileId());
        dto.setFullNumber(chargingPile.getCode() + dto.getCode());
        this.updateById(dto);
        return AjaxResult.success();
    }
    @Override
    public Map<String, ChargingGunCountVO> getChargingGunCount(Integer siteId) {
        Map<String, ChargingGunCountVO> map = new HashMap<>(4);
        //查询充电桩
        List<TChargingPile> pileList = chargingPileService.list(Wrappers.lambdaQuery(TChargingPile.class)
                .eq(TChargingPile::getSiteId, siteId));
        if(CollectionUtils.isEmpty(pileList)){
            map.put("superSufficient", new ChargingGunCountVO(0,0));
            map.put("fastSufficient", new ChargingGunCountVO(0,0));
            map.put("slowSufficient", new ChargingGunCountVO(0,0));
            map.put("totalSufficient", new ChargingGunCountVO(0,0));
            return map;
        }
        Set<Integer> pileIds = pileList.stream().map(TChargingPile::getId).collect(Collectors.toSet());
        // 查询全部充电枪
        List<TChargingGun> list = this.list(Wrappers.lambdaQuery(TChargingGun.class).eq(TChargingGun::getSiteId, siteId)
                .in(TChargingGun::getChargingPileId, pileIds));
        int freeCount = 0;
        // 超级充
        ChargingGunCountVO superSufficient = getGunCount(ChargingGunModeEnum.SUPER_SUFFICIENT.getCode(), list);
        freeCount += superSufficient.getFreeCount();
        map.put("superSufficient", superSufficient);
        // 快充
        ChargingGunCountVO fastSufficient = getGunCount(ChargingGunModeEnum.FAST_SUFFICIENT.getCode(), list);
        freeCount += fastSufficient.getFreeCount();
        map.put("fastSufficient", fastSufficient);
        // 慢充
        ChargingGunCountVO slowSufficient = getGunCount(ChargingGunModeEnum.SLOW_SUFFICIENT.getCode(), list);
        freeCount += slowSufficient.getFreeCount();
        map.put("slowSufficient", slowSufficient);
        ChargingGunCountVO chargingGunCountVO = new ChargingGunCountVO();
        chargingGunCountVO.setTotalCount(list.size());
        chargingGunCountVO.setFreeCount(freeCount);
        map.put("totalSufficient", chargingGunCountVO);
        return map;
    }
    @Override
    public GunStatusStatisticsVO gunStatusStatistics(List<Integer> siteIds) {
        GunStatusStatisticsVO gunStatusStatisticsVO = new GunStatusStatisticsVO();
        if(CollectionUtils.isEmpty(siteIds)){
            List<StatusModeStatisticsVO> statusModeStatistics = new ArrayList<>();
            for (int i = 1; i < 4; i++) {
                StatusModeStatisticsVO statusModeStatisticsVO = new StatusModeStatisticsVO();
                statusModeStatisticsVO.setChargeMode(i);
                statusModeStatisticsVO.setChargingCount(0);
                statusModeStatisticsVO.setFilledCount(0);
                statusModeStatisticsVO.setInsertCount(0);
                statusModeStatisticsVO.setFreeCount(0);
                statusModeStatistics.add(statusModeStatisticsVO);
            }
            gunStatusStatisticsVO.setStatusModeStatistics(statusModeStatistics);
        }
        List<Map<String, Object>> modeStatistics = this.baseMapper.getModeStatistics(siteIds);
        if(CollectionUtils.isEmpty(modeStatistics)){
            Map<String, Object> modeStatistics1 = new HashMap<>();
            modeStatistics1.put("1", "0");
            modeStatistics1.put("2", "0");
            modeStatistics1.put("3", "0");
            modeStatistics.add(modeStatistics1);
        }
        gunStatusStatisticsVO.setModeStatistics(modeStatistics);
        List<Map<String, Integer>> statusStatistics = new ArrayList<>();
        // 离线
        Long count = this.baseMapper.selectCount(Wrappers.lambdaQuery(TChargingGun.class)
                .eq(TChargingGun::getStatus, 1));
        HashMap<String, Integer> objectObjectHashMap1 = new HashMap<>();
        objectObjectHashMap1.put("charge_mode",1);
        objectObjectHashMap1.put("modeCount", count.intValue());
        statusStatistics.add(objectObjectHashMap1);
//        statusStatistics.put(1, count.intValue());
        // 故障
        count = this.baseMapper.selectCount(Wrappers.lambdaQuery(TChargingGun.class)
                .eq(TChargingGun::getStatus, 7));
        HashMap<String, Integer> objectObjectHashMap2 = new HashMap<>();
//        objectObjectHashMap2.put("2", count.intValue());
        objectObjectHashMap2.put("charge_mode",2);
        objectObjectHashMap2.put("modeCount", count.intValue());
        statusStatistics.add(objectObjectHashMap2);
//        statusStatistics.put(2, count.intValue());
        // 充电中
        count = this.baseMapper.selectCount(Wrappers.lambdaQuery(TChargingGun.class)
                .in(TChargingGun::getStatus, Arrays.asList(3,4,5,6)));
       HashMap<String, Integer> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("charge_mode",3);
        objectObjectHashMap.put("modeCount", count.intValue());
        statusStatistics.add(objectObjectHashMap);
//        statusStatistics.put(3, count.intValue());
        gunStatusStatisticsVO.setStatusStatistics(statusStatistics);
        List<StatusModeStatisticsVO> statusModeStatisticsVOS = new ArrayList<>();
        StatusModeStatisticsVO statusModeStatistics1 = this.baseMapper.getStatusModeStatistics(siteIds,1);
        StatusModeStatisticsVO statusModeStatistics2 = this.baseMapper.getStatusModeStatistics(siteIds,2);
        StatusModeStatisticsVO statusModeStatistics3 = this.baseMapper.getStatusModeStatistics(siteIds,3);
        if (statusModeStatistics1==null){
            StatusModeStatisticsVO vo = new StatusModeStatisticsVO();
            vo.setChargeMode(1);
            vo.setFreeCount(0);
            vo.setFilledCount(0);
            vo.setInsertCount(0);
            vo.setChargingCount(0);
            statusModeStatistics1 =vo;
        }
        statusModeStatisticsVOS.add(statusModeStatistics1);
        if (statusModeStatistics2==null){
            StatusModeStatisticsVO vo = new StatusModeStatisticsVO();
            vo.setChargeMode(2);
            vo.setFreeCount(0);
            vo.setFilledCount(0);
            vo.setInsertCount(0);
            vo.setChargingCount(0);
            statusModeStatistics2 =vo;
        }
        statusModeStatisticsVOS.add(statusModeStatistics2);
        if (statusModeStatistics3==null){
            StatusModeStatisticsVO vo = new StatusModeStatisticsVO();
            vo.setChargeMode(3);
            vo.setFreeCount(0);
            vo.setFilledCount(0);
            vo.setInsertCount(0);
            vo.setChargingCount(0);
            statusModeStatistics3 =vo;
        }
        statusModeStatisticsVOS.add(statusModeStatistics3);
        gunStatusStatisticsVO.setStatusModeStatistics(statusModeStatisticsVOS);
        return gunStatusStatisticsVO;
    }
    private ChargingGunCountVO getGunCount(Integer chargeMode, List<TChargingGun> list){
        ChargingGunCountVO chargingGunCountVO = new ChargingGunCountVO();
        chargingGunCountVO.setTotalCount(list.stream().filter(tChargingGun -> tChargingGun.getChargeMode().equals(chargeMode)).collect(Collectors.toList()).size());
        chargingGunCountVO.setFreeCount(list.stream().filter(tChargingGun -> tChargingGun.getChargeMode().equals(chargeMode)
                && tChargingGun.getStatus()== ChargingGunStatusEnum.IDLE.getCode()).collect(Collectors.toList()).size());
        return chargingGunCountVO;
    }
    /**
     * 校验必填项
     * @param dto
     * @return
     */
    AjaxResult addVerify(TChargingGunDTO dto){
        if(StringUtils.isEmpty(dto.getCode())){
            return AjaxResult.error("接口编码不能为空");
        }
        if(StringUtils.isEmpty(dto.getName())){
            return AjaxResult.error("接口名称不能为空");
        }
        if(null == dto.getType()){
            return AjaxResult.error("接口类型不能为空");
        }
        if(null == dto.getStatus()){
            return AjaxResult.error("接口状态不能为空");
        }
        if(null == dto.getChargeMode()){
            return AjaxResult.error("充电方式不能为空");
        }
        if(null == dto.getUpperRatedVoltage()){
            return AjaxResult.error("额定电压上限不能为空");
        }
        if(null == dto.getLowerLimitOfRatedVoltage()){
            return AjaxResult.error("额定电压下限不能为空");
        }
        if(null == dto.getRatedCurrent()){
            return AjaxResult.error("额定电流不能为空");
        }
        if(null == dto.getRatedPower()){
            return AjaxResult.error("额定功率不能为空");
        }
        if(StringUtils.isEmpty(dto.getNationalStandard())){
            return AjaxResult.error("国家标准不能为空");
        }
        return AjaxResult.success();
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java
New file
@@ -0,0 +1,275 @@
package com.ruoyi.chargingPile.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.chargingPile.api.dto.PageChargingPileListDTO;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.query.BatchSetAccountingStrategy;
import com.ruoyi.chargingPile.api.query.PageChargingPileList;
import com.ruoyi.chargingPile.api.vo.TChargingPileVO;
import com.ruoyi.chargingPile.mapper.TChargingPileMapper;
import com.ruoyi.chargingPile.service.TChargingGunService;
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
 * 充电桩 服务实现类
 * </p>
 *
 * @author xiaochen
 * @since 2024-08-06
 */
@Slf4j
@Service
public class TChargingPileServiceImpl extends ServiceImpl<TChargingPileMapper, TChargingPile> implements TChargingPileService {
    @Resource
    private TChargingGunService chargingGunService;
    @Resource
    private RedisTemplate redisTemplate;
    /**
     * 获取充电桩列表数据
     * @param page
     * @return
     */
    @Override
    public PageInfo<PageChargingPileListDTO> pageChargingPileList(PageChargingPileList page) {
        Set<Integer> siteIds = null;
        PageInfo<PageChargingPileListDTO> pageInfo = new PageInfo<>(page.getPageCurr(), page.getPageSize());
        List<PageChargingPileListDTO> list = this.baseMapper.pageChargingPileList(pageInfo, page, siteIds);
        return pageInfo.setRecords(list);
    }
    /**
     * 添加充电桩
     * @param chargingPile
     * @return
     */
    @Override
    public AjaxResult addChargingPile(TChargingPile chargingPile) {
        AjaxResult ajaxResult = addChargingPileVerify(chargingPile);
        if(ajaxResult.isError()){
            return ajaxResult;
        }
        long count = this.count(new LambdaQueryWrapper<TChargingPile>().eq(TChargingPile::getCode, chargingPile.getCode())
                .eq(TChargingPile::getDelFlag, 0));
        if(count > 0){
            return AjaxResult.error("设备编号已存在");
        }
        this.save(chargingPile);
        return AjaxResult.success();
    }
    /**
     * 校验必填项
     * @param chargingPile
     * @return
     */
    AjaxResult addChargingPileVerify(TChargingPile chargingPile){
        if(StringUtils.isEmpty(chargingPile.getCode())){
            return AjaxResult.error("设备编号不能为空");
        }
        if(StringUtils.isEmpty(chargingPile.getName())){
            return AjaxResult.error("充电设备名称不能为空");
        }
        if(null == chargingPile.getNumber()){
            return AjaxResult.error("桩号不能为空");
        }
        if(null == chargingPile.getType()){
            return AjaxResult.error("设备类型不能为空");
        }
        if(null == chargingPile.getSiteId()){
            return AjaxResult.error("归属电站不能为空");
        }
        if(null == chargingPile.getPartnerId()){
            return AjaxResult.error("归属合作商不能为空");
        }
        if(null == chargingPile.getRatedPower()){
            return AjaxResult.error("额定功率不能为空");
        }
        return AjaxResult.success();
    }
    /**
     * 获取充电桩详情
     * @param id 充电桩id
     * @return
     */
    @Override
    public TChargingPile getChargingPile(Integer id) {
        return this.baseMapper.getChargingPile(id);
    }
    /**
     * 编辑充电桩
     * @param chargingPile
     * @return
     */
    @Override
    public AjaxResult editChargingPile(TChargingPile chargingPile) {
        AjaxResult ajaxResult = addChargingPileVerify(chargingPile);
        if(ajaxResult.isError()){
            return ajaxResult;
        }
        TChargingPile one = this.getOne(new LambdaQueryWrapper<TChargingPile>().eq(TChargingPile::getCode, chargingPile.getCode())
                .eq(TChargingPile::getDelFlag, 0));
        if(null != one && !one.getId().equals(chargingPile.getId())){
            return AjaxResult.error("设备编号已存在");
        }
        this.updateById(chargingPile);
        List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, chargingPile.getId()).eq(TChargingGun::getDelFlag, 0));
        for (TChargingGun chargingGun : list) {
            TChargingGun chargingGun1 = new TChargingGun();
            chargingGun1.setId(chargingGun.getId());
            chargingGun1.setFullNumber(chargingPile.getCode() + chargingGun.getCode());
            chargingGun1.setSiteId(chargingPile.getSiteId());
            chargingGunService.updateById(chargingGun1);
        }
        return AjaxResult.success();
    }
    /**
     * 删除充电桩
     * @param ids
     * @return
     */
    @Override
    public AjaxResult delChargingPile(Integer[] ids) {
        //检查是否有关联数据
        long count = chargingGunService.count(new LambdaQueryWrapper<TChargingGun>().in(TChargingGun::getChargingPileId, Arrays.asList(ids))
                .eq(TChargingGun::getDelFlag, 0));
        if(count > 0){
            return AjaxResult.error("该充电桩已添加接口,不可删除。");
        }
        for (Integer id : ids) {
            TChargingPile chargingPile = this.getById(id);
            //调用华为Iot删除设备
//            if(StringUtils.isNotEmpty(chargingPile.getIotdDeviceId())){
//                ShowDeviceResp showDeviceResp = iotInterfaceClient.showDeviceRequest(chargingPile.getCode()).getData();
//                if(null != showDeviceResp){
//                    DeleteDeviceResp deleteDeviceResp = iotInterfaceClient.deleteDevice(chargingPile.getCode()).getData();
//                    if(null == deleteDeviceResp || (deleteDeviceResp.getHttpStatusCode() != 200 && deleteDeviceResp.getHttpStatusCode() != 201 && deleteDeviceResp.getHttpStatusCode() != 204)){
//                        return AjaxResult.error("删除设备异常,请查看华为设备管理");
//                    }
//                    chargingPile.setIotdDeviceId("");
//                }
//
//            }
            this.removeById(chargingPile);
        }
        return AjaxResult.success();
    }
    /**
     * 批量设置计费策略
     * @param setAccountingStrategy
     */
    @Override
    public void batchSetAccountingStrategy(BatchSetAccountingStrategy setAccountingStrategy) {
        List<Integer> id = setAccountingStrategy.getId();
        List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().in(TChargingGun::getChargingPileId, id).eq(TChargingGun::getDelFlag, 0));
        for (TChargingGun tChargingGun : list) {
            TChargingGun tChargingGun1 = new TChargingGun();
            tChargingGun1.setId(tChargingGun.getId());
            tChargingGun1.setAccountingStrategyId(setAccountingStrategy.getAccountingStrategyId());
            chargingGunService.updateById(tChargingGun1);
        }
    }
    @Override
    public List<TChargingPileVO> getChargingGunList(Integer siteId,Integer type) {
        LambdaQueryWrapper<TChargingGun> wrapper = new LambdaQueryWrapper<>();
        if(Objects.nonNull(type)){
            wrapper.eq(TChargingGun::getChargeMode, type);
        }
        wrapper.eq(TChargingGun::getSiteId, siteId);
        List<TChargingGun> chargingGuns = chargingGunService.list(wrapper);
        Set<Integer> collect = chargingGuns.stream().map(TChargingGun::getChargingPileId).collect(Collectors.toSet());
        List<TChargingPileVO> chargingPileVOS = new ArrayList<>();
        if(collect.size() > 0){
            List<TChargingPile> tChargingPiles = this.baseMapper.selectBatchIds(collect);
            for (TChargingPile tChargingPile : tChargingPiles) {
                TChargingPileVO vo = new TChargingPileVO();
                List<TChargingGun> chargingGunList = chargingGuns.stream().filter(gun -> gun.getChargingPileId().equals(tChargingPile.getId())).collect(Collectors.toList());
                for (TChargingGun chargingGun : chargingGunList) {
                    if(chargingGun.getStatus().equals(4)){
                        // 查询正在充电的单子的实时记录
                    }
                    if(chargingGun.getStatus().equals(5)){
                        chargingGun.setSoc(100);
                    }
                }
                vo.setChargingGunList(chargingGunList);
                vo.setId(tChargingPile.getId());
                vo.setCode(tChargingPile.getCode());
                vo.setName(tChargingPile.getName());
                vo.setNumber(tChargingPile.getNumber());
                chargingPileVOS.add(vo);
            }
        }
        return chargingPileVOS;
    }
    /**
     * 定时任务修改充电桩状态
     */
    @Override
    public void updateStatus() {
        //查询出redis集合汇总符合条件的数据
        Set keys = redisTemplate.opsForHash().keys("charging_gun_online");
        List<String> fullNumbers = new ArrayList<>();
        keys.forEach(key -> {
                        Long time = (Long) redisTemplate.opsForHash().get("charging_gun_online", key);
                        if(null != time && System.currentTimeMillis() - time > 300000){
                            log.info("设备编号:{} 已离线", key);
                            log.info("间隔时间", System.currentTimeMillis() - time);
                            fullNumbers.add(key.toString());
                        }
        });
        if(fullNumbers.size() == 0){
            return;
        }
        //处理符合条件的数据,修改设备状态
        List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().in(TChargingGun::getFullNumber, fullNumbers).eq(TChargingGun::getDelFlag, 0));
        for (TChargingGun chargingGun : list) {
            TChargingGun chargingGun1 = new TChargingGun();
            chargingGun1.setId(chargingGun.getId());
            chargingGun1.setStatus(1);
            chargingGunService.updateById(chargingGun1);
            //桩处于正常,桩所属的枪都处于非正常,修改桩状态为异常
            TChargingPile chargingPile = this.getById(chargingGun.getChargingPileId());
            List<TChargingGun> list1 = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, chargingPile.getId()).eq(TChargingGun::getDelFlag, 0));
            int size = list1.stream().filter(s -> s.getStatus() == 1 || s.getStatus() == 7).collect(Collectors.toList()).size();
            if(chargingPile.getStatus() == 1 && list1.size() == size){
                TChargingPile chargingPile1 = new TChargingPile();
                chargingPile1.setId(chargingGun.getChargingPileId());
                chargingPile1.setStatus(2);
                this.updateById(chargingPile1);
            }
        }
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/util/QRCodeUtils.java
New file
@@ -0,0 +1,267 @@
package com.ruoyi.chargingPile.util;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Random;
/**
 * 二维码工具类
 */
public class QRCodeUtils {
    private static Logger logger = LoggerFactory.getLogger(QRCodeUtils.class);
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;
    private static BufferedImage createImage(String content, String imgPath,
                                             boolean needCompress) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
                BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
                        : 0xFFFFFFFF);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // 插入图片
        QRCodeUtils.insertImage(image, imgPath, needCompress);
        return image;
    }
    /**
     * 插入LOGO
     *
     * @param source
     *            二维码图片
     * @param imgPath
     *            LOGO图片地址
     * @param needCompress
     *            是否压缩
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, String imgPath,
                                    boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            logger.debug(""+imgPath+"   该文件不存在!");
            return;
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // 压缩LOGO
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height,
                    Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图
            g.dispose();
            src = image;
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }
    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content
     *            内容
     * @param imgPath
     *            LOGO地址
     * @param destPath
     *            存放目录
     * @param needCompress
     *            是否压缩LOGO
     * @throws Exception
     */
    public static String encode(String content, String imgPath, String destPath,
                                boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtils.createImage(content, imgPath,
                needCompress);
        mkdirs(destPath);
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
        return destPath;
    }
    /**
     * 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
     * @date 2013-12-11 上午10:16:36
     * @param destPath 存放目录
     */
    public static void mkdirs(String destPath) {
        File file =new File(destPath);
        //当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }
    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content
     *            内容
     * @param imgPath
     *            LOGO地址
     * @param destPath
     *            存储地址
     * @throws Exception
     */
    public static void encode(String content, String imgPath, String destPath)
            throws Exception {
        QRCodeUtils.encode(content, imgPath, destPath, false);
    }
    /**
     * 生成二维码
     *
     * @param content
     *            内容
     * @param destPath
     *            存储地址
     * @param needCompress
     *            是否压缩LOGO
     * @throws Exception
     */
    public static void encode(String content, String destPath,
                              boolean needCompress) throws Exception {
        QRCodeUtils.encode(content, null, destPath, needCompress);
    }
    /**
     * 生成二维码
     *
     * @param content
     *            内容
     * @param destPath
     *            存储地址
     * @throws Exception
     */
    public static void encode(String content, String destPath) throws Exception {
        QRCodeUtils.encode(content, null, destPath, false);
    }
    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content
     *            内容
     * @param imgPath
     *            LOGO地址
     * @param output
     *            输出流
     * @param needCompress
     *            是否压缩LOGO
     * @throws Exception
     */
    public static void encode(String content, String imgPath,
                              OutputStream output, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtils.createImage(content, imgPath,
                needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }
    /**
     * 生成二维码
     *
     * @param content
     *            内容
     * @param output
     *            输出流
     * @throws Exception
     */
    public static void encode(String content, OutputStream output)
            throws Exception {
        QRCodeUtils.encode(content, null, output, false);
    }
    /**
     * 解析二维码
     *
     * @param file
     *            二维码图片
     * @return
     * @throws Exception
     */
    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(
                image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }
    /**
     * 解析二维码
     *
     * @param path
     *            二维码图片地址
     * @return
     * @throws Exception
     */
    public static String decode(String path) throws Exception {
        return QRCodeUtils.decode(new File(path));
    }
    public static void main(String[] args) throws Exception {
        String text = "http://www.baidu.com";  //这里设置自定义网站url
        String logoPath = "C:\\Users\\admin\\Desktop\\test\\test.jpg";
        String destPath = "C:\\Users\\admin\\Desktop\\test\\";
        logger.debug(QRCodeUtils.encode(text, logoPath, destPath, true));
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/util/TaskUtil.java
New file
@@ -0,0 +1,26 @@
package com.ruoyi.chargingPile.util;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
 * 定时任务工具类
 */
@Component
public class TaskUtil implements ApplicationListener<WebServerInitializedEvent> {
    private Integer port = null;
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        port = event.getWebServer().getPort();
        System.out.println("端口号:" + port);
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/resources/bootstrap.yml
New file
@@ -0,0 +1,96 @@
server:
  port: 9300
  tomcat:
    basedir: /mnt/tomcat
# Spring
spring:
  application:
    # 应用名称
    name: ruoyi-chargingPile
  main:
    allow-bean-definition-overriding: true
    allow-circular-references: true
  profiles:
    # 环境配置
    active: dev
#    active: prod
---
spring:
  config:
    activate:
      on-profile: dev
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 192.168.110.169:8848
        service: ${spring.application.name}
        group: DEFAULT_GROUP
        namespace: cf61067f-5267-48e4-a3d8-ac9746f51c01
        username: nacos
        password: nacos
      config:
        # 配置中心地址
        server-addr: 192.168.110.169:8848
        namespace: cf61067f-5267-48e4-a3d8-ac9746f51c01
        username: nacos
        password: nacos
        group: DEFAULT_GROUP
        name: ${spring.application.name}
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
---
spring:
  config:
    activate:
      on-profile: prod
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 47.120.5.122:8848
        service: ${spring.application.name}
        group: DEFAULT_GROUP
        namespace: 508d0707-50dd-48b0-ad27-349e7bb3c9eb
        username: nacos
        password: nacos
      config:
        # 配置中心地址
        server-addr: 47.120.5.122:8848
        namespace: 508d0707-50dd-48b0-ad27-349e7bb3c9eb
        username: nacos
        password: nacos
        group: DEFAULT_GROUP
        name: ${spring.application.name}
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
---
spring:
  config:
    activate:
      on-profile: test
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 192.168.110.169:8848
        service: ${spring.application.name}
        group: DEFAULT_GROUP
        namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce
      config:
        # 配置中心地址
        server-addr: 192.168.110.169:8848
        namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce
        group: DEFAULT_GROUP
        name: ${spring.application.name}
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
ruoyi-service/ruoyi-chargingPile/src/main/resources/logback.xml
New file
@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="/data/log/app/ruoyi-chargingPile"/>
    <!--0. 日志格式和颜色渲染 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <!--1. 输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--2. 输出到文档-->
    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/debug.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/info.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/warn.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.4 level为 ERROR 日志,时间滚动输出  -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/error.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.5 所有 除了DEBUG级别的其它高于DEBUG的 日志,记录到一个文件  -->
    <appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/all.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档记录除了DEBUG级别的其它高于DEBUG的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
    </appender>
    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
        <logger name="org.springframework.web" level="info"/>
        <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
    -->
    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->
    <!-- 4  最终的策略:
                 基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)-->
    <springProfile name="dev">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
        <logger name="com.stylefeng.guns.modular.system.dao" level="debug"/>
    </springProfile>
    <springProfile name="test">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
    </springProfile>
    <springProfile name="prod">
        <root level="info">
            <!-- 生产环境最好不配置console写文件 -->
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
    </springProfile>
</configuration>
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
New file
@@ -0,0 +1,322 @@
<?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="com.ruoyi.chargingPile.mapper.SiteMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.chargingPile.api.model.Site">
        <id column="id" property="id" />
        <result column="user_id" property="userId" />
        <result column="`code`" property="code" />
        <result column="`name`" property="name" />
        <result column="site_type" property="siteType" />
        <result column="business_category" property="businessCategory" />
        <result column="status" property="status" />
        <result column="construction_site" property="constructionSite" />
        <result column="img_url" property="imgUrl" />
        <result column="province" property="province" />
        <result column="province_code" property="provinceCode" />
        <result column="city" property="city" />
        <result column="city_code" property="cityCode" />
        <result column="districts" property="districts" />
        <result column="districts_code" property="districtsCode" />
        <result column="lon" property="lon" />
        <result column="lat" property="lat" />
        <result column="address" property="address" />
        <result column="country_code" property="countryCode" />
        <result column="phone" property="phone" />
        <result column="service_phone" property="servicePhone" />
        <result column="guide" property="guide" />
        <result column="start_service_time" property="startServiceTime" />
        <result column="end_service_time" property="endServiceTime" />
        <result column="service_description" property="serviceDescription" />
        <result column="vehicle_description" property="vehicleDescription" />
        <result column="parking_space" property="parkingSpace" />
        <result column="rate_description" property="rateDescription" />
        <result column="space_charge_explain" property="spaceChargeExplain" />
        <result column="accounting_strategy_id" property="accountingStrategyId" />
        <result column="establishment_time" property="establishmentTime" />
        <result column="sort" property="sort" />
        <result column="remark" property="remark" />
        <result column="annual_service_fee" property="annualServiceFee" />
        <result column="create_time" property="createTime" />
        <result column="del_flag" property="delFlag" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, partner_id, code, `name`, site_type, business_category, status, construction_site, img_url, province, province_code,
          city, city_code, districts, districts_code, lon, lat, address, country_code, phone, service_phone, guide, start_service_time,
          end_service_time, service_description, vehicle_description, parking_space, rate_description, space_charge_explain,
          accounting_strategy_id, establishment_time, sort, remark,annual_service_fee, create_time, del_flag
    </sql>
    <select id="getSiteList" resultType="com.ruoyi.chargingPile.api.dto.GetSiteListDTO">
        select
        a.id,
        a.code,
        a.name,
        a.partner_id as partnerId,
        b.name as partnerName,
        a.site_type as siteType,
        a.business_category as businessCategory,
        a.status,
        CONCAT(a.province, a.city, a.districts, a.address) as address,
        a.phone,
        a.service_phone as servicePhone,
        a.parking_space as parkingSpace,
        DATE_FORMAT(a.establishment_time, '%Y-%m-%d %H:%i:%s') as establishmentTime,
        c.num as chargingPileNumber,
        a.sort,
        a.lon,
        a.lat,
        a.accounting_strategy_id as accountingStrategyId,
        if(a.accounting_strategy_id is null, 1, if(d.site_id is null, 1, 2)) as accountingStrategyType
        from t_site a
        left join t_partner b on (a.partner_id = b.id)
        left join (select site_id, count(1) as num from t_charging_pile where del_flag = 0 group by site_id) c on (a.id = c.site_id)
        left join t_accounting_strategy d on (a.accounting_strategy_id = d.id)
        WHERE a.del_flag = 0
        <if test="null != item.name and '' != item.name">
            and a.name like CONCAT('%', #{item.name}, '%')
        </if>
        <if test="null != item.partnerName and '' != item.partnerName">
            and b.name like CONCAT('%', #{item.partnerName}, '%')
        </if>
        <if test="null != item.siteType">
            and a.site_type = #{item.siteType}
        </if>
        <if test="null != item.businessCategory">
            and a.business_category = #{item.businessCategory}
        </if>
        <if test="null != item.status">
            and a.status = #{item.status}
        </if>
        <if test="null != item.provinceCode and '' != item.provinceCode">
            and a.province_code = #{item.provinceCode}
        </if>
        <if test="null != item.cityCode and '' != item.cityCode">
            and a.city_code = #{item.cityCode}
        </if>
        <if test="null != item.districtsCode and '' != item.districtsCode">
            and a.districts_code = #{item.districtsCode}
        </if>
        <if test="null != ids and ids.size() > 0">
            and a.id in
            <foreach collection="ids" item="itemm" index="index" open="(" separator="," close=")">
                #{itemm}
            </foreach>
        </if>
        order by a.sort desc, a.create_time desc
    </select>
    <select id="pageList" resultType="com.ruoyi.chargingPile.api.vo.SiteVO">
        select
        ts.id, ts.partner_id, ts.code, ts.`name`, ts.site_type, ts.business_category, ts.status, ts.construction_site, ts.img_url,
        ts.lon, ts.lat, ts.address, ts.country_code, ts.phone,ts.guide, ts.service_description, ts.vehicle_description,
        ts.parking_space, ts.rate_description, ts.space_charge_explain, ts.accounting_strategy_id,ts.del_flag,tcg.fastCount,
        tcg.slowCount,tcg.superCount,tasd.electrovalence,tasd.vipElectrovalence,tasd.serviceCharge,tasd.electrovalenceOriginal,tcg.superFreeCount,tcg.fastFreeCount,tcg.slowFreeCount,
        ROUND(
        6378.138 * 2 * ASIN(
        SQRT(
        POW(
        SIN(
        (
        #{query.lat} * PI() / 180 - ts.lat * PI() / 180
        ) / 2
        ),
        2
        ) + COS(#{query.lat} * PI() / 180) * COS(ts.lat * PI() / 180) * POW(
        SIN(
        (
        #{query.lon} * PI() / 180 - ts.lon * PI() / 180
        ) / 2
        ),
        2
        )
        )
        ) * 1000
        ) AS distance
        from t_site ts
        left join (
        select site_id,
            SUM(CASE WHEN charge_mode = 1 THEN 1 ELSE 0 END) AS superCount,
            SUM(CASE WHEN charge_mode = 2 THEN 1 ELSE 0 END) AS fastCount,
            SUM(CASE WHEN charge_mode = 3 THEN 1 ELSE 0 END) AS slowCount,
            SUM(CASE WHEN charge_mode = 1 and `status` = 2 THEN 1 ELSE 0 END) AS superFreeCount,
            SUM(CASE WHEN charge_mode = 2 and `status` = 2 THEN 1 ELSE 0 END) AS fastFreeCount,
            SUM(CASE WHEN charge_mode = 3 and `status` = 2 THEN 1 ELSE 0 END) AS slowFreeCount
        from
            t_charging_gun
        where
            del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        group by
            site_id) tcg on (ts.id = tcg.site_id)
        left join (
        select
            a.accounting_strategy_id,
            a.service_charge AS serviceCharge,
            a.electrovalence AS electrovalenceOriginal,
            (a.electrovalence+a.service_charge) AS electrovalence,
            (a.electrovalence + (a.service_charge*(CASE WHEN b.discount IS NULL THEN 1 ELSE b.discount END))) AS vipElectrovalence
        from
            t_accounting_strategy_detail a
        left join
                t_accounting_strategy b on (a.accounting_strategy_id = b.id)
        where b.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        AND DATE_FORMAT(NOW(), '%H:%i:%s') between a.start_time and
        CASE WHEN a.end_time = '00:00' THEN '23:59:59' ELSE a.end_time END) tasd on (ts.accounting_strategy_id = tasd.accounting_strategy_id)
        <where>
            <if test="null != query.name and '' != query.name">
                and ts.`name` like CONCAT('%', #{query.name}, '%')
            </if>
            <if test="null != query.cityCode and '' != query.cityCode">
                and ts.city_code = #{query.cityCode}
            </if>
            AND ts.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
            AND ts.status = ${@com.ruoyi.common.core.enums.status.SiteStatusEnum@NORMAL_USE.getCode()}
            AND ts.accounting_strategy_id IS NOT NULL
        </where>
        <if test="query.sortType != null">
            <choose>
                <when test="query.sortType == 1">
                    ORDER BY distance ASC
                </when>
                <when test="query.sortType == 2">
                    ORDER BY tasd.electrovalence ASC
                </when>
                <when test="query.sortType == 3">
                    ORDER BY (tcg.fastCount + tcg.slowCount + tcg.superCount) DESC
                </when>
            </choose>
        </if>
    </select>
    <select id="getDetailById" resultType="com.ruoyi.chargingPile.api.vo.SiteDetailVO">
        SELECT id, partner_id, code, `name`, site_type, business_category, status, construction_site, img_url, province, province_code,
               city, city_code, districts, districts_code, lon, lat, address, country_code, phone, service_phone, guide, start_service_time,
               end_service_time, service_description, vehicle_description, parking_space, rate_description, space_charge_explain,
               accounting_strategy_id, establishment_time, sort, remark, create_time, del_flag, mark,
            ROUND(
        6378.138 * 2 * ASIN(
        SQRT(
        POW(
        SIN(
        (
        #{query.lat} * PI() / 180 - lat * PI() / 180
        ) / 2
        ),
        2
        ) + COS(#{query.lat} * PI() / 180) * COS(lat * PI() / 180) * POW(
        SIN(
        (
        #{query.lon} * PI() / 180 - lon * PI() / 180
        ) / 2
        ),
        2
        )
        )
        ) * 1000
        ) AS distance
        FROM t_site WHERE id = #{query.siteId} AND del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
    </select>
    <select id="getSiteListParkLot" resultType="com.ruoyi.chargingPile.api.model.Site">
        select ts.id, ts.partner_id, ts.code, ts.`name`, ts.site_type, ts.business_category, ts.status
        from t_site ts
        <where>
            <if test="null != ids and ids.size()>0">
                AND ts.id IN
                <foreach collection="ids" item="id" index="index" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
            AND ts.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        </where>
    </select>
    <select id="getSiteListGun" resultType="com.ruoyi.chargingPile.api.model.Site">
        select <include refid="Base_Column_List"></include>
        from t_site
        <where>
            <if test="null != ids and ids.size()>0">
                AND id IN
                <foreach collection="ids" item="id" index="index" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
            AND del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        </where>
    </select>
    <select id="getMapSiteList" resultType="com.ruoyi.chargingPile.api.vo.SiteVO">
        select
        ts.id, ts.partner_id, ts.code, ts.`name`, ts.site_type, ts.business_category, ts.status, ts.construction_site, ts.img_url,
        ts.lon, ts.lat, ts.address, ts.country_code, ts.phone,ts.guide, ts.service_description, ts.vehicle_description,
        ts.parking_space, ts.rate_description, ts.space_charge_explain, ts.accounting_strategy_id,ts.del_flag,tcg.fastCount,
        tcg.slowCount,tcg.superCount,tasd.electrovalence,tasd.vipElectrovalence,tcg.superFreeCount,tcg.fastFreeCount,tcg.slowFreeCount,
        ROUND(
        6378.138 * 2 * ASIN(
        SQRT(
        POW(
        SIN(
        (
        #{query.lat} * PI() / 180 - ts.lat * PI() / 180
        ) / 2
        ),
        2
        ) + COS(#{query.lat} * PI() / 180) * COS(ts.lat * PI() / 180) * POW(
        SIN(
        (
        #{query.lon} * PI() / 180 - ts.lon * PI() / 180
        ) / 2
        ),
        2
        )
        )
        ) * 1000
        ) AS distance
        from t_site ts
        left join (
        select site_id,
        SUM(CASE WHEN charge_mode = 1 THEN 1 ELSE 0 END) AS superCount,
        SUM(CASE WHEN charge_mode = 2 THEN 1 ELSE 0 END) AS fastCount,
        SUM(CASE WHEN charge_mode = 3 THEN 1 ELSE 0 END) AS slowCount,
        SUM(CASE WHEN charge_mode = 1 and `status` = 2 THEN 1 ELSE 0 END) AS superFreeCount,
        SUM(CASE WHEN charge_mode = 2 and `status` = 2 THEN 1 ELSE 0 END) AS fastFreeCount,
        SUM(CASE WHEN charge_mode = 3 and `status` = 2 THEN 1 ELSE 0 END) AS slowFreeCount
        from
        t_charging_gun
        where
        del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        group by
        site_id) tcg on (ts.id = tcg.site_id)
        left join (
        select
        a.accounting_strategy_id,
        a.service_charge AS serviceCharge,
        a.electrovalence AS electrovalenceOriginal,
        (a.electrovalence+a.service_charge) AS electrovalence,
        (a.electrovalence+(a.service_charge*(CASE WHEN b.discount IS NULL THEN 1 ELSE b.discount END))) AS vipElectrovalence
        from
        t_accounting_strategy_detail a
        left join
        t_accounting_strategy b on (a.accounting_strategy_id = b.id)
        where b.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        AND DATE_FORMAT(NOW(), '%H:%i:%s') between a.start_time AND
        CASE WHEN a.end_time = '00:00' THEN '23:59:59' ELSE a.end_time END) tasd on (ts.accounting_strategy_id = tasd.accounting_strategy_id)
        <where>
            <if test="null != query.name and '' != query.name">
                and ts.`name` like CONCAT('%', #{query.name}, '%')
            </if>
            <if test="null != query.cityCode and '' != query.cityCode">
                and ts.city_code = #{query.cityCode}
            </if>
            AND ts.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
            AND ts.status = ${@com.ruoyi.common.core.enums.status.SiteStatusEnum@NORMAL_USE.getCode()}
        </where>
        <if test="query.sortType != null">
            <choose>
                <when test="query.sortType == 1">
                    ORDER BY distance ASC
                </when>
            </choose>
        </if>
    </select>
</mapper>
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TAccountingStrategyDetailMapper.xml
New file
@@ -0,0 +1,35 @@
<?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="com.ruoyi.chargingPile.mapper.TAccountingStrategyDetailMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail">
        <id column="id" property="id" />
        <result column="accounting_strategy_id" property="accountingStrategyId" />
        <result column="`type`" property="type" />
        <result column="start_time" property="startTime" />
        <result column="end_time" property="endTime" />
        <result column="electrovalence" property="electrovalence" />
        <result column="service_charge" property="serviceCharge" />
        <result column="cost_service_charge" property="costServiceCharge" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, accounting_strategy_id, `type`, start_time, end_time, electrovalence, service_charge, cost_service_charge
    </sql>
    <select id="queryAccountingStrategyDetailByStrategyId" resultType="com.ruoyi.chargingPile.api.vo.TAccountingStrategyDetailVO">
        SELECT
            tasd.id, tasd.accounting_strategy_id, tasd.`type`, tasd.start_time, tasd.end_time, ROUND(tasd.electrovalence,4) AS electrovalence,
            ROUND(tasd.service_charge,4) AS serviceCharge,ROUND(tasd.cost_service_charge,4) AS costServiceCharge,tas.discount
        FROM t_accounting_strategy_detail tasd
        LEFT JOIN t_accounting_strategy tas ON tas.id = tasd.accounting_strategy_id
        <where>
            tasd.del_flag = 0
            <if test="strategyId != null">
                AND tasd.accounting_strategy_id = #{strategyId}
            </if>
        </where>
    </select>
</mapper>
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TAccountingStrategyMapper.xml
New file
@@ -0,0 +1,72 @@
<?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="com.ruoyi.chargingPile.mapper.TAccountingStrategyMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.chargingPile.api.model.TAccountingStrategy">
        <id column="id" property="id" />
        <result column="site_id" property="siteId" />
        <result column="`name`" property="name" />
        <result column="description" property="description" />
        <result column="discount" property="discount" />
        <result column="first_user_id" property="firstUserId" />
        <result column="two_user_id" property="twoUserId" />
        <result column="first_remark" property="firstRemark" />
        <result column="two_remark" property="twoRemark" />
        <result column="audit_status" property="auditStatus" />
        <result column="first_audit_time" property="firstAuditTime" />
        <result column="two_audit_time" property="twoAuditTime" />
        <result column="create_time" property="createTime" />
        <result column="del_flag" property="delFlag" />
        <result column="parent_id" property="parentId" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, site_id, `name`, description, discount,first_user_id,two_user_id,first_remark,two_remark,audit_status,first_audit_time,two_audit_time, create_time, del_flag,parent_id
    </sql>
    <select id="pageList" resultType="com.ruoyi.chargingPile.api.vo.TAccountingStrategyVO">
        SELECT
        id, site_id, `name`, description, discount,first_user_id,two_user_id,first_remark,two_remark,audit_status,first_audit_time,two_audit_time, create_time, del_flag,user_id,parent_id
        FROM t_accounting_strategy
        <where>
            <if test="query.name != null and query.name != ''">
                AND `name` LIKE concat('%',#{query.name}, '%')
            </if>
            <if test="query.auditStatus != null">
                AND audit_status = #{query.auditStatus}
            </if>
            AND site_id IS NULL
            AND (parent_id IS NULL OR audit_status = 3 OR audit_status = 4)
            AND del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        </where>
        ORDER BY create_time DESC
    </select>
    <select id="pageList1" resultType="com.ruoyi.chargingPile.api.vo.TAccountingStrategyVO">
        SELECT
        id, site_id, `name`, description, discount,first_user_id,two_user_id,first_remark,two_remark,audit_status,first_audit_time,two_audit_time, create_time, del_flag,user_id,parent_id
        FROM t_accounting_strategy
        <where>
            <if test="query.name != null and query.name != ''">
                AND `name` LIKE concat('%',#{query.name}, '%')
            </if>
            <if test="query.auditStatus != null">
                AND audit_status = #{query.auditStatus}
            </if>
            AND site_id IS NULL
            AND (parent_id IS NULL OR audit_status = 1 OR audit_status = 2)
        </where>
        ORDER BY create_time DESC
    </select>
    <select id="getPlatformAccountingStrategy" resultType="com.ruoyi.chargingPile.api.vo.TAccountingStrategyVO">
        SELECT
            id, site_id, `name`, description, discount,first_user_id,two_user_id,first_remark,two_remark,audit_status,first_audit_time,two_audit_time, create_time, del_flag,parent_id
        FROM t_accounting_strategy where del_flag = 0 and site_id is not null order by create_time desc
    </select>
</mapper>
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml
New file
@@ -0,0 +1,107 @@
<?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="com.ruoyi.chargingPile.mapper.TChargingGunMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.chargingPile.api.model.TChargingGun">
        <id column="id" property="id" />
        <result column="code" property="code" />
        <result column="site_id" property="siteId" />
        <result column="partner_id" property="partnerId" />
        <result column="charging_pile_id" property="chargingPileId" />
        <result column="`name`" property="name" />
        <result column="`type`" property="type" />
        <result column="status" property="status" />
        <result column="charge_mode" property="chargeMode" />
        <result column="accounting_strategy_id" property="accountingStrategyId" />
        <result column="upper_rated_voltage" property="upperRatedVoltage" />
        <result column="lower_limit_of_rated_voltage" property="lowerLimitOfRatedVoltage" />
        <result column="rated_current" property="ratedCurrent" />
        <result column="rated_power" property="ratedPower" />
        <result column="charging_power" property="chargingPower" />
        <result column="parking_number" property="parkingNumber" />
        <result column="parking_status" property="parkingStatus" />
        <result column="parking_lock_state" property="parkingLockState" />
        <result column="national_standard" property="nationalStandard" />
        <result column="remark" property="remark" />
        <result column="create_time" property="createTime" />
        <result column="del_flag" property="delFlag" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, code, site_id, partner_id, charging_pile_id, `name`, `type`, status, charge_mode, accounting_strategy_id, upper_rated_voltage, lower_limit_of_rated_voltage, rated_current, rated_power, parking_number, parking_status, parking_lock_state, national_standard, remark, create_time, del_flag
    </sql>
    <select id="pageList" resultType="com.ruoyi.chargingPile.api.vo.TChargingGunVO">
        SELECT
            tcg.*,
        tas.name AS strategyName
        FROM t_charging_gun tcg
        LEFT JOIN t_accounting_strategy tas ON tas.id = tcg.accounting_strategy_id
        <where>
            <if test="query.siteId != null">
                AND tcg.site_id = #{query.siteId}
            </if>
            <if test="query.chargingPileId != null">
                AND tcg.charging_pile_id = #{query.chargingPileId}
            </if>
            <if test="query.name != null and query.name != ''">
                AND tcg.`name` LIKE concat('%',#{query.name},'%')
            </if>
            <if test="query.type != null">
                AND tcg.`type` = #{query.type}
            </if>
            <if test="query.status != null">
                AND tcg.status = #{query.status}
            </if>
            <if test="query.chargeMode != null">
                AND tcg.charge_mode = #{query.chargeMode}
            </if>
            <if test="null != siteIds and siteIds.size() > 0">
                and tcg.site_id in
                <foreach collection="siteIds" index="index" item="item" open="(" separator="," close=")">
                    #{item}
                </foreach>
            </if>
            AND tcg.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        </where>
        ORDER BY tcg.create_time DESC
    </select>
    <select id="getStatusModeStatistics" resultType="com.ruoyi.chargingPile.api.vo.StatusModeStatisticsVO">
        SELECT
        charge_mode,
        IFNULL((SELECT COUNT(*) FROM t_charging_gun WHERE status = 2 AND charge_mode = #{chargeMode} and del_flag = 0),0) AS freeCount,
        IFNULL((SELECT COUNT(*) FROM t_charging_gun WHERE status = 5 AND charge_mode = #{chargeMode} and del_flag = 0),0) AS filledCount,
        IFNULL((SELECT COUNT(*) FROM t_charging_gun WHERE status = 3 AND charge_mode = #{chargeMode} and del_flag = 0),0) AS insertCount,
        IFNULL((SELECT COUNT(*) FROM t_charging_gun WHERE status = 4 AND charge_mode = #{chargeMode} and del_flag = 0),0) AS chargingCount
        FROM t_charging_gun
        WHERE del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()} AND charge_mode = #{chargeMode}
        AND charging_pile_id in (
        select id from `charging_pile_service`.`t_charging_pile` where  del_flag = 0
        )
        <if test="siteIds != null and siteIds.size()>0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
        GROUP BY charge_mode
    </select>
    <select id="getModeStatistics" resultType="java.util.Map">
        SELECT
        charge_mode,
        IFNULL(COUNT(charge_mode),0) AS modeCount
        FROM t_charging_gun
        WHERE del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        AND charging_pile_id in (
        select id from `charging_pile_service`.`t_charging_pile` where  del_flag = 0
        )
        <if test="siteIds != null and siteIds.size()>0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
        GROUP BY charge_mode
    </select>
</mapper>
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingPileMapper.xml
New file
@@ -0,0 +1,83 @@
<?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="com.ruoyi.chargingPile.mapper.TChargingPileMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.chargingPile.api.model.TChargingPile">
        <id column="id" property="id" />
        <result column="code" property="code" />
        <result column="name" property="name" />
        <result column="number" property="number" />
        <result column="type" property="type" />
        <result column="site_id" property="siteId" />
        <result column="partner_id" property="partnerId" />
        <result column="manufacturer_code" property="manufacturerCode" />
        <result column="manufacturer" property="manufacturer" />
        <result column="equipment_type" property="equipmentType" />
        <result column="production_date" property="productionDate" />
        <result column="rated_power" property="ratedPower" />
        <result column="charging_station_number" property="chargingStationNumber" />
        <result column="status" property="status" />
        <result column="create_time" property="createTime" />
        <result column="del_flag" property="delFlag" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, code, `name`, `number`, `type`, site_id, partner_id, manufacturer_code, manufacturer, equipment_type, production_date, rated_power, charging_station_number, status, create_time, del_flag
    </sql>
    <select id="pageChargingPileList" resultType="com.ruoyi.chargingPile.api.dto.PageChargingPileListDTO">
        select
        a.id,
        a.code,
        a.name,
        a.number,
        a.type,
        a.site_id as siteId,
        b.name as siteName,
        a.partner_id as partnerId,
        c.name as partnerName,
        a.manufacturer,
        a.equipment_type as equipmentType,
        a.rated_power as ratedPower
        from t_charging_pile a
        left join t_site b on (a.site_id = b.id)
        left join t_partner c on (a.partner_id = c.id)
        where a.del_flag = 0
        <if test="null != item.siteId">
            and a.site_id = #{item.siteId}
        </if>
        <if test="null != item.name and '' != item.name">
            and a.name like CONCAT('%', #{item.name}, '%')
        </if>
        <if test="null != item.type">
            and a.type = #{item.type}
        </if>
        <if test="null != siteIds and siteIds.size() > 0">
            and a.site_id in
            <foreach collection="siteIds" item="itemm" index="index" open="(" separator="," close=")">
                #{itemm}
            </foreach>
        </if>
        order by a.create_time desc
    </select>
    <select id="getChargingPile" resultMap="BaseResultMap">
        select
        a.*,
        b.name as siteName,
        c.name as partnerName
        from t_charging_pile a
        left join t_site b on (a.site_id = b.id)
        left join t_partner c on (a.partner_id = c.id)
        where a.id = #{id}
    </select>
    <select id="getChargingGunList" resultType="com.ruoyi.chargingPile.api.vo.TChargingPileVO">
        select id,code, `name`, `number` from t_charging_pile
        where del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()} and site_id = #{siteId}
    </select>
</mapper>
ruoyi-service/ruoyi-chargingPile/src/main/resources/mybatis-config.xml
New file
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration  PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 打印查询语句 不会写入到日志文件中-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--<setting name="logImpl" value="LOG4J" />-->
        <!-- 控制全局缓存(二级缓存),按美团技术团队的说法,尽量别用缓存机制 emmmm.... -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false  -->
        <!-- <setting name="lazyLoadingEnabled" value="true"/> -->
        <setting name="mapUnderscoreToCamelCase" value="false"/><!--是否将map下划线方式转为驼峰式命名-->
        <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖-->
        <!-- <setting name="aggressiveLazyLoading" value="false"/>-->
        <!--  Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
        <!--<setting name="proxyFactory" value="CGLIB" />-->
        <!-- 关于mybatis的一二级缓存 请参照:https://tech.meituan.com/2018/01/19/mybatis-cache.html -->
        <!-- 一级缓存范围默认:SESSION ,此范围在复杂应用场景中可能会出现脏读数据-->
        <!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 -->
        <!--<setting name="localCacheScope" value="STATEMENT"/>-->
        <setting name="localCacheScope" value="STATEMENT"/>
    </settings>
</configuration>
ruoyi-service/ruoyi-chargingPile/src/test/java/com/ruoyi/chargingPile/RuoYiChargingPileApplicationTests.java
New file
@@ -0,0 +1,21 @@
//package com.ruoyi.chargingPile;
//
//import com.alibaba.fastjson2.JSON;
//import com.ruoyi.chargingPile.api.dto.GetPermissionConfigurationDTO;
//import com.ruoyi.chargingPile.service.IPartnerService;
//import org.junit.jupiter.api.Test;
//import org.springframework.boot.test.context.SpringBootTest;
//
//import javax.annotation.Resource;
//
//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RuoYiChargingPileApplication.class)
//public class RuoYiChargingPileApplicationTests {
//    @Resource
//    private IPartnerService partnerService;
//
//    @Test
//    public void test(){
//        GetPermissionConfigurationDTO permissionConfiguration = partnerService.getPermissionConfiguration(9, 15);
//        System.err.println(JSON.toJSONString(permissionConfiguration));
//    }
//}