longz
2026-08-04 14ac49d64602ddcf3b5057601e829f29f078b2f2
fix:碳减排量
11个文件已修改
198 ■■■■■ 已修改文件
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/factory/ChargingOrderFallbackFactory.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/feignClient/ChargingOrderClient.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/service/impl/TScreenContentServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/vo/EmissionReductionVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TScreenContentServiceImpl.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/vo/EmissionReductionVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/factory/ChargingOrderFallbackFactory.java
@@ -225,6 +225,11 @@
            }
            @Override
            public R<BigDecimal> getLargeScreenTotalCapacity(@RequestParam("siteIds") List<Integer> siteIds){
                return R.fail("获取站点集合累计充电量失败:" + throwable.getMessage());
            }
            @Override
            public R<List<Long>> getAppUserIdsBySiteIds(List<Integer> siteIds) {
                return R.fail("查询站点充电用户失败:" + throwable.getMessage());
            }
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/feignClient/ChargingOrderClient.java
@@ -327,6 +327,12 @@
    R<BigDecimal> getSumDegreeBySiteIds(@RequestParam("siteIds") List<Integer> SiteIds);
    /**
     * 充电桩大屏 获取站点集合中累计充电量(已结束+已支付订单口径, 与 large-screen/summary 一致)
     */
    @GetMapping("/t-charging-order/getLargeScreenTotalCapacity")
    R<BigDecimal> getLargeScreenTotalCapacity(@RequestParam("siteIds") List<Integer> siteIds);
    /**
     * 查询指定站点中实际发生过充电的用户ID
     */
    @PostMapping("/t-charging-order/getAppUserIdsBySiteIds")
ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/service/impl/TScreenContentServiceImpl.java
@@ -40,33 +40,31 @@
    @Override
    public EmissionReductionVO emissionReduction(List<Integer> siteIds) {
        ScreenTopVO top = top(Arrays.asList(25, 26));
        //需调用接口 计算光伏减排
        EmissionReductionVO vo = new EmissionReductionVO();
        //获取总电量 计算累计充电二氧化碳减排量
        BigDecimal charge=top.getCarCharge();
        //获取总电量 计算累计充电二氧化碳减排量(与大屏累计充电量同口径: 已结束+已支付订单)
        BigDecimal charge = BigDecimal.ZERO;
        R<BigDecimal> r = chargingOrderClient.getLargeScreenTotalCapacity(siteIds);
        if (r.getCode() == 200 && r.getData() != null) {
            charge = r.getData();
        }
        BigDecimal multiplier = new BigDecimal("0.1564");
        //计算累计充电二氧化碳减排量
        if (charge.compareTo(BigDecimal.ZERO) != 0) {
            // 定义乘数和除数
           // 0.1404
            // 计算:charge × 0.1404 ÷ 1000
            // 计算:charge × 0.1564 ÷ 1000
            charge = charge
                    .multiply(multiplier)      // 乘以 0.1404
                    .divide(new BigDecimal("1000"),2, RoundingMode.HALF_DOWN); // 除以 1000,保留6位小数,四舍五入
                    .multiply(multiplier)      // 乘以 0.1564
                    .divide(new BigDecimal("1000"),2, RoundingMode.HALF_DOWN); // 除以 1000,保留2位小数,四舍五入
        }
//        vo.setCharge(charge);
        vo.setCharge(charge.add(new BigDecimal(32.61)));
        vo.setCharge(charge);
        //获取累计储能放电量
        String s = KsolarUtils.getElectricity().split("_")[0];
        vo.setEnergyStorage(new BigDecimal(s).multiply(multiplier)      // 乘以 0.1404
        vo.setEnergyStorage(new BigDecimal(s).multiply(multiplier)      // 乘以 0.1564
                .divide(new BigDecimal("1000"),2, RoundingMode.HALF_DOWN));
        vo.setEnergyStorage(vo.getEnergyStorage().add(new BigDecimal(0.31)));
        //获取累计发电
        vo.setPhotovoltaic(KsolarUtils.getYearAllEnergy());
        vo.setPhotovoltaic(vo.getPhotovoltaic().add(new BigDecimal(4.2)));
        //总数:
        BigDecimal total = vo.getPhotovoltaic().add(vo.getEnergyStorage()).add(vo.getCharge());
@@ -84,7 +82,7 @@
    //百分比计算
    public static BigDecimal calculateRatio(BigDecimal part, BigDecimal total) {
        if (total.compareTo(BigDecimal.ZERO) == 0) {
            throw new ArithmeticException("分母不能为零");
            return BigDecimal.ZERO;
        }
        return part.divide(total, 4, RoundingMode.HALF_UP);
    }
@@ -120,9 +118,9 @@
        BigDecimal carCharge=new BigDecimal("0.00");
        BigDecimal greenElectricity=new BigDecimal("0.00");
        if (siteIds!=null && !siteIds.isEmpty()){
            //获取充电量
            R<BigDecimal> r = chargingOrderClient.getSumDegreeBySiteIds(Arrays.asList(25,26));
            if (r.getCode()==200){
            //获取充电量(与大屏累计充电量同口径: 已结束+已支付订单)
            R<BigDecimal> r = chargingOrderClient.getLargeScreenTotalCapacity(siteIds);
            if (r.getCode()==200 && r.getData()!=null){
                charge=r.getData();
            }
            //汽车放电量
ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/vo/EmissionReductionVO.java
@@ -8,7 +8,7 @@
@Data
public class EmissionReductionVO {
    @ApiModelProperty("累计光伏发电二氧化碳减排量(吨)")
    private BigDecimal photovoltaic = new BigDecimal("1.39");
    private BigDecimal photovoltaic;
    @ApiModelProperty("累计光伏发电二氧化碳减排量(占比率)")
    private BigDecimal photovoltaicRate ;
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java
@@ -3168,6 +3168,15 @@
        return R.ok(new BigDecimal(sumDegreeBySiteIds));
    }
    /**
     * 充电桩数据大屏 获取站点集合中累计充电量(与 /large-screen/summary 同口径: 已结束+已支付订单)
     */
    @ResponseBody
    @GetMapping("/getLargeScreenTotalCapacity")
    public R<BigDecimal> getLargeScreenTotalCapacity(@RequestParam("siteIds") List<Integer> siteIds){
        return R.ok(chargingOrderService.getLargeScreenTotalCapacity(siteIds));
    }
    @ResponseBody
    @PostMapping("/addChargingOrder")
    public R<Long> addChargingOrder(@RequestBody TChargingOrder chargingOrder){
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
@@ -15,7 +15,6 @@
import com.ruoyi.order.api.vo.ChargingOrderBalanceIncomeDetailVO;
import com.ruoyi.order.api.vo.TChargingOrderVo;
import com.ruoyi.order.dto.*;
import com.ruoyi.order.vo.OrderCountByDate;
import com.ruoyi.order.vo.LargeChargingPowerVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -236,6 +235,9 @@
    // 接口用: 注册用户数(G 行)
    Long registeredFromStat();
    // 接口用: 大屏累计充电量(M 行汇总, 与 summaryFromStat 同源)
    BigDecimal capacityFromStat(@Param("siteIds") List<Integer> siteIds);
    SixChargingDto getLargeScreenSettlementIncome(@Param("siteIdsCsv") String siteIdsCsv,
                                                  @Param("startTime") String startTime,
                                                  @Param("endTime") String endTime);
@@ -265,7 +267,9 @@
    Long countCar(@Param("brands") List<String> brands);
    List<OrderCountByDate> countOrdersByDate(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("gunIds") List<Integer> gunIds);
    Long countOrdersInRangeByGunIds(@Param("startTime") LocalDateTime startTime,
                                    @Param("endTime") LocalDateTime endTime,
                                    @Param("gunIds") List<Integer> gunIds);
    Double getSumDegreeBySiteIds(@Param("siteIds") List<Integer> siteIds);
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java
@@ -321,6 +321,11 @@
    List<LargeChargingPowerVo> getLargeScreenChargingPower(List<Integer> siteIds, LocalDateTime startTime, LocalDateTime endTime);
    /**
     * 大屏累计充电量(与 /large-screen/summary 同口径: 已结束+已支付订单, 读预聚合表 M 行)
     */
    BigDecimal getLargeScreenTotalCapacity(List<Integer> siteIds);
    /**
     * 重建大屏预聚合表(每日全量: 全部月份切片 + 近90天日切片 + 全局注册用户数)
     */
    void rebuildLargeScreenStat();
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -68,7 +68,6 @@
import com.ruoyi.order.vo.EndOfChargePageInfo;
import com.ruoyi.order.vo.ChargingSimulationVO;
import com.ruoyi.order.vo.IcbcAdminSubOrderVO;
import com.ruoyi.order.vo.OrderCountByDate;
import com.ruoyi.order.vo.StatisticsOfBatteryVO;
import com.ruoyi.order.vo.LargeChargingPowerVo;
import com.ruoyi.order.vo.ReservationRecommendationVO;
@@ -6809,6 +6808,26 @@
    }
    @Override
    public BigDecimal getLargeScreenTotalCapacity(List<Integer> siteIds) {
        String cacheKey = largeScreenCacheKey("capacity", siteIds);
        BigDecimal cached = redisService.getCacheObject(cacheKey);
        if (cached != null) {
            return cached;
        }
        BigDecimal capacity = BigDecimal.ZERO;
        try {
            BigDecimal fromStat = this.baseMapper.capacityFromStat(siteIds);
            if (fromStat != null) {
                capacity = fromStat;
            }
        } catch (Exception e) {
            log.warn("大屏累计充电量读取预聚合表失败, siteIds={}", siteIds, e);
        }
        redisService.setCacheObject(cacheKey, capacity, LARGE_SCREEN_CACHE_SECONDS, TimeUnit.SECONDS);
        return capacity;
    }
    @Override
    public void rebuildLargeScreenStat() {
        log.info("大屏预聚合表全量重建开始");
        long start = System.currentTimeMillis();
@@ -7329,6 +7348,11 @@
     */
    @Override
    public R<StatisticsOfBatteryVO> getStatisticsOfBattery(List<Integer> siteIds) {
        String cacheKey = largeScreenCacheKey("battery", siteIds);
        StatisticsOfBatteryVO cached = redisService.getCacheObject(cacheKey);
        if (cached != null) {
            return R.ok(cached);
        }
        StatisticsOfBatteryVO vo = new StatisticsOfBatteryVO();
        List<Integer> effectiveSiteIds = siteIds == null ? Arrays.asList(25, 26) : siteIds;
        if (effectiveSiteIds.isEmpty()) {
@@ -7343,39 +7367,52 @@
            return R.ok(vo);
        }
        List<Integer> gunIds = r.getData();
        //统计
        // 统计: gunIds 分批查询, 避免超大 IN 列表撑爆 MyCat 规划器
        Long total = 0L;
        if (gunIds != null && !gunIds.isEmpty()) {
            total = this.baseMapper.selectCount(new LambdaQueryWrapper<TChargingOrder>()
                    .eq(TChargingOrder::getDelFlag, 0)//未删除
                    .in(TChargingOrder::getStatus, Arrays.asList(3, 5))//充电中、已结束
                    .in(TChargingOrder::getChargingGunId, gunIds));//符合条件的充电枪
            for (List<Integer> chunk : chunkList(gunIds, 500)) {
                Long chunkCount = this.baseMapper.selectCount(new LambdaQueryWrapper<TChargingOrder>()
                        .eq(TChargingOrder::getDelFlag, 0)//未删除
                        .in(TChargingOrder::getStatus, Arrays.asList(3, 5))//充电中、已结束
                        .in(TChargingOrder::getChargingGunId, chunk));//符合条件的充电枪
                total += chunkCount == null ? 0L : chunkCount;
            }
        }
        vo.setTotal(total.intValue());
        List<LocalDate> dates = new ArrayList<>();
        List<Integer> counts = new ArrayList<>();
        LocalDate today = LocalDate.now();
        LocalDateTime startDate = today.minusDays(7).atStartOfDay();
        LocalDateTime endDate = today.minusDays(1).atTime(LocalTime.MAX);
        Map<LocalDate, Long> countByDate = new HashMap<>();
        if (gunIds != null && !gunIds.isEmpty()) {
            List<OrderCountByDate> orderCounts = this.baseMapper.countOrdersByDate(startDate, endDate, gunIds);
            if (orderCounts != null) {
                for (OrderCountByDate orderCount : orderCounts) {
                    countByDate.put(orderCount.getDate(), orderCount.getCount());
                }
            }
        }
        for (int i = 7; i >= 1; i--) {//升序
            LocalDate day = today.minusDays(i);
            LocalDateTime dayStart = day.atStartOfDay();
            LocalDateTime dayEnd = day.plusDays(1).atStartOfDay();
            long dayCount = 0L;
            if (gunIds != null && !gunIds.isEmpty()) {
                for (List<Integer> chunk : chunkList(gunIds, 500)) {
                    Long chunkCount = this.baseMapper.countOrdersInRangeByGunIds(dayStart, dayEnd, chunk);
                    dayCount += chunkCount == null ? 0L : chunkCount;
                }
            }
            dates.add(day);
            counts.add(countByDate.getOrDefault(day, 0L).intValue());
            counts.add((int) dayCount);
        }
        vo.setDates(dates);
        vo.setCounts(counts);
        redisService.setCacheObject(cacheKey, vo, LARGE_SCREEN_CACHE_SECONDS, TimeUnit.SECONDS);
        return R.ok(vo);
    }
    /**
     * 列表分批, 控制单条 SQL 的 IN 列表规模
     */
    private <T> List<List<T>> chunkList(List<T> list, int size) {
        List<List<T>> chunks = new ArrayList<>();
        for (int i = 0; i < list.size(); i += size) {
            chunks.add(list.subList(i, Math.min(i + size, list.size())));
        }
        return chunks;
    }
    @Override
    public Double getSumDegreeBySiteIds(List<Integer> siteIds) {
        Double sumDegreeBySiteIds = this.baseMapper.getSumDegreeBySiteIds(siteIds);
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -2535,21 +2535,19 @@
    </select>
    <select id="countOrdersByDate" resultType="com.ruoyi.order.vo.OrderCountByDate">
        SELECT DATE(create_time) AS `date`, COUNT(*) AS `count`
    <!-- 电池安全检测按日计数: 单日有界 COUNT, 无 GROUP BY/ORDER BY, 规避 MyCat 规划器
         在函数列上排序(MycatMemSort)失败的报错; 天级分组由 Java 端循环完成 -->
    <select id="countOrdersInRangeByGunIds" resultType="java.lang.Long">
        SELECT COUNT(1)
        FROM t_charging_order
        WHERE
        del_flag = 0
        and
        status in (3,5)
        and charging_gun_id in
        WHERE del_flag = 0
          AND status IN (3, 5)
          AND charging_gun_id IN
        <foreach item="item" index="index" collection="gunIds" open="(" separator="," close=")">
            #{item}
        </foreach>
        and create_time BETWEEN #{startTime} AND #{endTime}
        GROUP BY DATE(create_time)
        ORDER BY DATE(create_time) ASC
          AND create_time &gt;= #{startTime}
          AND create_time &lt; #{endTime}
    </select>
@@ -3244,4 +3242,17 @@
          AND site_id = 0
        LIMIT 1
    </select>
    <!-- 接口用: 大屏累计充电量(与 summary 同源: 已结束+已支付订单, M 行汇总) -->
    <select id="capacityFromStat" resultType="java.math.BigDecimal">
        SELECT COALESCE(SUM(capacity), 0)
        FROM t_large_screen_site_stat
        WHERE stat_type = 'M'
        <if test="siteIds != null and siteIds.size() > 0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
    </select>
</mapper>
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TScreenContentServiceImpl.java
@@ -34,20 +34,21 @@
    @Override
    public EmissionReductionVO emissionReduction(List<Integer> siteIds) {
        ScreenTopVO top = top(siteIds);
        //需调用接口 计算光伏减排
        EmissionReductionVO vo = new EmissionReductionVO();
        //获取总电量 计算累计充电二氧化碳减排量
        BigDecimal charge = top.getCarCharge();
        //获取总电量 计算累计充电二氧化碳减排量(与大屏累计充电量同口径: 已结束+已支付订单)
        BigDecimal charge = BigDecimal.ZERO;
        R<BigDecimal> r = chargingOrderClient.getLargeScreenTotalCapacity(siteIds);
        if (r.getCode() == 200 && r.getData() != null) {
            charge = r.getData();
        }
        BigDecimal multiplier = new BigDecimal("0.1564");
        //计算累计充电二氧化碳减排量
        if (charge.compareTo(BigDecimal.ZERO) != 0) {
            // 定义乘数和除数
            // 0.1404
            // 计算:charge × 0.1404 ÷ 1000
            // 计算:charge × 0.1564 ÷ 1000
            charge = charge
                    .multiply(multiplier)      // 乘以 0.1404
                    .divide(new BigDecimal("1000"), 2, RoundingMode.HALF_DOWN); // 除以 1000,保留6位小数,四舍五入
                    .multiply(multiplier)      // 乘以 0.1564
                    .divide(new BigDecimal("1000"), 2, RoundingMode.HALF_DOWN); // 除以 1000,保留2位小数,四舍五入
        }
        vo.setCharge(charge);
@@ -112,9 +113,9 @@
        BigDecimal carCharge = new BigDecimal("0.00");
        BigDecimal greenElectricity = new BigDecimal("0.00");
        if (siteIds != null && !siteIds.isEmpty()) {
            //获取充电量
            R<BigDecimal> r = chargingOrderClient.getSumDegreeBySiteIds(siteIds);
            if (r.getCode() == 200) {
            //获取充电量(与大屏累计充电量同口径: 已结束+已支付订单)
            R<BigDecimal> r = chargingOrderClient.getLargeScreenTotalCapacity(siteIds);
            if (r.getCode() == 200 && r.getData() != null) {
                charge = r.getData();
            }
            //汽车放电量
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/vo/EmissionReductionVO.java
@@ -8,7 +8,7 @@
@Data
public class EmissionReductionVO {
    @ApiModelProperty("累计光伏发电二氧化碳减排量(吨)")
    private BigDecimal photovoltaic = new BigDecimal("1.39");
    private BigDecimal photovoltaic;
    @ApiModelProperty("累计光伏发电二氧化碳减排量(占比率)")
    private BigDecimal photovoltaicRate ;