puzhibing
2026-09-02 bf82d9f70479a5ea99ff2ea00b35cb3b6b7d500f
修改刷卡充电订单查询报错
1个文件已添加
5个文件已修改
153 ■■■■■ 已修改文件
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TCardChargingOrderMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TCardChargingOrderMapper.xml 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/CardChargingOrderSummaryMapperTest.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TCardChargingOrderSummaryTest.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/20260902_add_charging_order_vin.sql 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TCardChargingOrderMapper.java
@@ -41,6 +41,8 @@
    Map<String, Object> accountingSummaryByOrderIds(@Param("orderIds") List<Long> orderIds);
    List<Map<String, Object>> capacitySummaryByOrderIds(@Param("orderIds") List<Long> orderIds);
    List<Map<String, Object>> balanceIncomeDetail(@Param("query") CardChargingOrderQuery query);
    List<Map<String, Object>> accountingStrategyList(@Param("chargingOrderId") Long chargingOrderId);
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java
@@ -316,10 +316,38 @@
        query.setSiteIds(siteIds);
    }
    private void fillElectronicProportion(List<ChargingOrderVO> list) {
        List<Long> orderIds = list.stream().map(ChargingOrderVO::getId).filter(Objects::nonNull).collect(Collectors.toList());
        if (orderIds.isEmpty()) {
            return;
        }
        List<Map<String, Object>> capacityRows = new ArrayList<>();
        int batchSize = 500;
        for (int i = 0; i < orderIds.size(); i += batchSize) {
            List<Long> batchIds = orderIds.subList(i, Math.min(i + batchSize, orderIds.size()));
            capacityRows.addAll(Optional.ofNullable(baseMapper.capacitySummaryByOrderIds(batchIds))
                    .orElse(Collections.emptyList()));
        }
        Map<Long, Map<String, Object>> capacityByOrderId = capacityRows.stream()
                .filter(item -> item.get("orderId") != null)
                .collect(Collectors.toMap(item -> Long.valueOf(item.get("orderId").toString()), item -> item, (a, b) -> a));
        for (ChargingOrderVO order : list) {
            Map<String, Object> capacity = capacityByOrderId.get(order.getId());
            Map<String, BigDecimal> summary = emptyAccountingSummary();
            if (capacity != null) {
                for (String key : new String[]{"capacityTotal", "capacity1", "capacity2", "capacity3", "capacity4"}) {
                    summary.put(key, summaryDecimal(capacity, key));
                }
            }
            order.setElectronicProportion(buildProportion(summary, "capacity"));
        }
    }
    private void fillPageExtra(List<ChargingOrderVO> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        fillElectronicProportion(list);
        List<Integer> siteIds = list.stream().map(ChargingOrderVO::getSiteId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<Integer> gunIds = list.stream().map(ChargingOrderVO::getChargingGunId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<Long> carIds = list.stream().map(ChargingOrderVO::getAppUserCarId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TCardChargingOrderMapper.xml
@@ -39,22 +39,8 @@
    </sql>
    <select id="pageList" resultType="com.ruoyi.order.api.vo.ChargingOrderVO">
        SELECT o.*,
               CONCAT(IFNULL(ROUND(a.capacity1 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(a.capacity2 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(a.capacity3 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(a.capacity4 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%') AS electronicProportion
        SELECT o.*
        FROM t_card_charging_order o
        LEFT JOIN (
            SELECT charging_order_id,
                   SUM(charging_capacity) AS capacity_total,
                   SUM(CASE WHEN type = 1 THEN charging_capacity ELSE 0 END) AS capacity1,
                   SUM(CASE WHEN type = 2 THEN charging_capacity ELSE 0 END) AS capacity2,
                   SUM(CASE WHEN type = 3 THEN charging_capacity ELSE 0 END) AS capacity3,
                   SUM(CASE WHEN type = 4 THEN charging_capacity ELSE 0 END) AS capacity4
            FROM t_card_charging_order_accounting_strategy
            GROUP BY charging_order_id
        ) a ON a.charging_order_id = o.id
        <include refid="queryCondition"/>
        ORDER BY o.create_time DESC
        LIMIT #{offset}, #{pageSize}
@@ -122,6 +108,21 @@
        </foreach>
    </select>
    <select id="capacitySummaryByOrderIds" resultType="java.util.LinkedHashMap">
        SELECT charging_order_id AS orderId,
               IFNULL(SUM(charging_capacity), 0) AS capacityTotal,
               IFNULL(SUM(CASE WHEN type = 1 THEN charging_capacity ELSE 0 END), 0) AS capacity1,
               IFNULL(SUM(CASE WHEN type = 2 THEN charging_capacity ELSE 0 END), 0) AS capacity2,
               IFNULL(SUM(CASE WHEN type = 3 THEN charging_capacity ELSE 0 END), 0) AS capacity3,
               IFNULL(SUM(CASE WHEN type = 4 THEN charging_capacity ELSE 0 END), 0) AS capacity4
        FROM t_card_charging_order_accounting_strategy
        WHERE charging_order_id IN
        <foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
            #{orderId}
        </foreach>
        GROUP BY charging_order_id
    </select>
    <select id="balanceIncomeDetail" resultType="java.util.LinkedHashMap">
        SELECT o.card_id AS cardId,
               o.card_no AS cardNo,
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/CardChargingOrderSummaryMapperTest.java
@@ -18,11 +18,16 @@
    @Test
    void splitsSummaryQueriesForMyCatAndRequiresCompleteTimeRanges() throws IOException {
        String mapper = resource("mapper/order/TCardChargingOrderMapper.xml");
        String pageList = select(mapper, "pageList");
        String summary = select(mapper, "summary");
        String orderIds = select(mapper, "summaryOrderIds");
        String share = select(mapper, "shareIncomeSummaryByOrderIds");
        String accounting = select(mapper, "accountingSummaryByOrderIds");
        String capacity = select(mapper, "capacitySummaryByOrderIds");
        assertTrue(pageList.contains("SELECT o.*"));
        assertFalse(pageList.contains(" JOIN "));
        assertFalse(pageList.contains("t_card_charging_order_accounting_strategy"));
        assertTrue(summary.contains("FROM t_card_charging_order o"));
        assertFalse(summary.contains(" JOIN "));
        assertFalse(summary.contains("t_card_charging_order_share_record"));
@@ -30,6 +35,8 @@
        assertTrue(orderIds.contains("<include refid=\"queryCondition\"/>"));
        assertTrue(share.contains("charging_order_id IN"));
        assertTrue(accounting.contains("charging_order_id IN"));
        assertTrue(capacity.contains("charging_order_id AS orderId"));
        assertTrue(capacity.contains("GROUP BY charging_order_id"));
        assertTrue(mapper.contains("startTime1 != null and startTime1 != '' and startTime2 != null and startTime2 != ''"));
        assertTrue(mapper.contains("endTime1 != null and endTime1 != '' and endTime2 != null and endTime2 != ''"));
    }
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TCardChargingOrderSummaryTest.java
@@ -16,6 +16,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -24,6 +25,34 @@
class TCardChargingOrderSummaryTest {
    @Test
    void fillsElectronicProportionFromCapacitySummaryInBatches() {
        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
        TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class);
        ReflectionTestUtils.setField(service, "baseMapper", mapper);
        List<com.ruoyi.order.api.vo.ChargingOrderVO> orders = new ArrayList<>();
        for (long id = 1; id <= 501; id++) {
            com.ruoyi.order.api.vo.ChargingOrderVO order = new com.ruoyi.order.api.vo.ChargingOrderVO();
            order.setId(id);
            orders.add(order);
        }
        Map<String, Object> capacity = new HashMap<>();
        capacity.put("orderId", 1L);
        capacity.put("capacityTotal", new BigDecimal("10"));
        capacity.put("capacity1", new BigDecimal("4"));
        capacity.put("capacity2", new BigDecimal("3"));
        capacity.put("capacity3", new BigDecimal("2"));
        capacity.put("capacity4", BigDecimal.ONE);
        doReturn(Collections.singletonList(capacity), Collections.emptyList())
                .when(mapper).capacitySummaryByOrderIds(anyList());
        ReflectionTestUtils.invokeMethod(service, "fillElectronicProportion", orders);
        assertEquals("40%-30%-20%-10%", orders.get(0).getElectronicProportion());
        assertEquals("0%-0%-0%-0%", orders.get(500).getElectronicProportion());
        verify(mapper, times(2)).capacitySummaryByOrderIds(anyList());
    }
    @Test
    void mergesShareAndAccountingSummariesInBatches() {
        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
        TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class);
sql/20260902_add_charging_order_vin.sql
New file
@@ -0,0 +1,56 @@
-- Add VIN snapshot column to every physical charging-order shard.
-- Execute directly on the backend MySQL instance, not through the database proxy.
-- The procedure is idempotent and only alters existing tables that lack the column.
USE `charging_pile_order`;
DROP PROCEDURE IF EXISTS `add_charging_order_vin`;
DELIMITER $$
CREATE PROCEDURE `add_charging_order_vin`()
BEGIN
    DECLARE shard_no INT DEFAULT 0;
    DECLARE target_table VARCHAR(64);
    DECLARE table_exists INT DEFAULT 0;
    DECLARE column_exists INT DEFAULT 0;
    WHILE shard_no < 50 DO
        SET target_table = CONCAT('t_charging_order_', shard_no);
        SELECT COUNT(*) INTO table_exists
        FROM information_schema.tables
        WHERE table_schema = DATABASE()
          AND table_name = target_table;
        SELECT COUNT(*) INTO column_exists
        FROM information_schema.columns
        WHERE table_schema = DATABASE()
          AND table_name = target_table
          AND column_name = 'vin';
        IF table_exists = 1 AND column_exists = 0 THEN
            SET @ddl = CONCAT(
                'ALTER TABLE `', target_table,
                '` ADD COLUMN `vin` varchar(17) NULL AFTER `reservation_time`'
            );
            PREPARE stmt FROM @ddl;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;
        END IF;
        SET shard_no = shard_no + 1;
    END WHILE;
END$$
DELIMITER ;
CALL `add_charging_order_vin`();
DROP PROCEDURE `add_charging_order_vin`;
SELECT COUNT(*) AS shard_count,
       SUM(CASE WHEN c.column_name = 'vin' THEN 1 ELSE 0 END) AS vin_column_count
FROM information_schema.tables t
LEFT JOIN information_schema.columns c
       ON c.table_schema = t.table_schema
      AND c.table_name = t.table_name
      AND c.column_name = 'vin'
WHERE t.table_schema = DATABASE()
  AND t.table_name REGEXP '^t_charging_order_[0-9]+$';