longz
2026-08-04 e67c67d99119e35c9fd476ea674f42f84b7153f4
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?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.order.mapper.TChargingOrderMapper">
@@ -195,7 +195,7 @@
        a.app_user_id
        FROM
        charging_pile_order.t_charging_order a
        where a.recharge_payment_status = 2
        where (a.recharge_payment_status = 2 OR a.status = -1 OR #{data.invoiceId} IS NOT NULL)
        UNION ALL
@@ -216,7 +216,7 @@
        a.app_user_id
        FROM
        charging_pile_order.t_shopping_order a
        where a.payment_status = 2
        where (a.payment_status = 2 OR #{data.invoiceId} IS NOT NULL)
        UNION ALL
@@ -237,7 +237,7 @@
        a.app_user_id
        FROM
        charging_pile_order.t_vip_order a
        where a.payment_status = 2
        where (a.payment_status = 2 OR #{data.invoiceId} IS NOT NULL)
        UNION ALL
@@ -291,118 +291,18 @@
            </if>
        </where>
        ORDER BY o.create_time desc
        ORDER BY COALESCE(o.pay_time, o.create_time, o.end_time) DESC, o.create_time DESC, o.id DESC
    </select>
    <select id="getRefundList" resultType="com.ruoyi.order.api.model.TChargingOrderRefund">
        select * from (
        SELECT
        re.id,
        re.`code`,
        re.refund_code,
        re.refund_title,
        re.refund_reason,
        re.refund_amount,
        re.balance_refund_amount,
        re.third_refund_amount,
        re.refund_total_amount,
        re.refund_time,
        re.pay_type,
        re.pay_amount,
        re.refund_remark,
        co.recharge_serial_number as serail_number,
        co.payment_amount,
        co.create_time as pay_time,
        co.id as order_id,
        co.app_user_id as user_id,
        co.site_id as site_id,
        co.pay_method as pay_method,
        1 as type
        FROM t_charging_order_refund re
        LEFT JOIN t_charging_order co ON re.charging_order_id = co.id
        <if test="data.specialRefund != null and data.specialRefund">
            WHERE re.refund_title = '特殊退款处理'
        </if>
        <if test="data.specialRefund == null or !data.specialRefund">
        UNION ALL
        SELECT
        re.id,
        re.`code`,
        re.refund_code,
        re.refund_title,
        re.refund_reason,
        re.refund_amount,
        0 as balance_refund_amount,
        re.refund_amount as third_refund_amount,
        re.refund_total_amount,
        re.refund_time,
        re.pay_type,
        re.pay_amount,
        re.refund_remark,
        so.serial_number,
        so.payment_amount,
        so.create_time as pay_time,
        so.id as order_id,
        so.app_user_id as user_id,
        null as site_id,
        3 as pay_method,
        2 as type
        FROM t_shopping_order_refund re
        LEFT JOIN t_shopping_order so on re.shopping_order_id = so.id
        UNION ALL
        SELECT
        vr.id,
        vr.`code`,
        vr.refund_code,
        vr.refund_title,
        vr.refund_reason,
        vr.refund_amount,
        0 as balance_refund_amount,
        vr.refund_amount as third_refund_amount,
        vr.refund_total_amount,
        vr.refund_time,
        vr.pay_type,
        vr.pay_amount,
        vr.refund_remark,
        vo.serial_number,
        vo.payment_amount,
        vo.create_time as pay_time,
        vo.id as order_id,
        vo.app_user_id as user_id,
        null as site_id,
        3 as pay_method,
        3 as type
        FROM t_vip_order_refund vr
        LEFT JOIN t_vip_order vo on vr.vip_order_id = vo.id
        </if>
        ) o
        <where>
            <if test="data.code != null and data.code != ''">
                AND o.code LIKE CONCAT('%',#{data.code},'%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND o.refund_code LIKE CONCAT('%',#{data.refundCode},'%')
            </if>
            <if test="data.serialNumber != null and data.serialNumber != ''">
                AND o.serail_number LIKE CONCAT('%',#{data.serialNumber},'%')
            </if>
            <if test="data.specialRefund != null and data.specialRefund">
                AND o.refund_title = '特殊退款处理'
            </if>
            <if test="data.siteIds != null and data.siteIds.size() > 0">
                AND (o.type != 1 OR o.site_id IN
                <foreach collection="data.siteIds" item="siteId" open="(" separator="," close=")">
                    #{siteId}
                </foreach>
                )
            </if>
        </where>
        order by o.refund_time desc
    </select>
    <select id="getRefundListWithoutOrderJoin" resultType="com.ruoyi.order.api.model.TChargingOrderRefund">
    <!--
        退款列表(筛选逆反查版)。serialNumber/siteIds 筛选时,先由 Service 按条件查出订单 id 列表,
        再按各类型订单 id IN 过滤退款表(IN 为退款表分片键,MyCat 可路由),替代跨分片 LEFT JOIN。
        type1/type2/type3 订单 id:null = 不过滤;空列表 = 无匹配(AND 1=0)。
        各分支同样内联 ORDER BY + LIMIT 下推。
    -->
    <select id="getRefundListByOrderIds" resultType="com.ruoyi.order.api.model.TChargingOrderRefund">
        SELECT * FROM (
        SELECT
        (SELECT
        re.id,
        re.`code`,
        re.refund_code,
@@ -429,10 +329,31 @@
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
            <choose>
                <when test="type1OrderIds != null and type1OrderIds.size() > 0">
                    AND re.charging_order_id IN
                    <foreach collection="type1OrderIds" item="id" open="(" separator="," close=")">
                        #{id}
                    </foreach>
                </when>
                <otherwise>
                    <if test="type1OrderIds != null">
                        AND 1 = 0
                    </if>
                </otherwise>
            </choose>
        </where>
        ORDER BY re.refund_time DESC
        LIMIT #{branchLimit})
        <if test="data.specialRefund == null or !data.specialRefund">
        UNION ALL
        SELECT
        (SELECT
        re.id,
        re.`code`,
        re.refund_code,
@@ -456,9 +377,30 @@
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
            <choose>
                <when test="type2OrderIds != null and type2OrderIds.size() > 0">
                    AND re.shopping_order_id IN
                    <foreach collection="type2OrderIds" item="id" open="(" separator="," close=")">
                        #{id}
                    </foreach>
                </when>
                <otherwise>
                    <if test="type2OrderIds != null">
                        AND 1 = 0
                    </if>
                </otherwise>
            </choose>
        </where>
        ORDER BY re.refund_time DESC
        LIMIT #{branchLimit})
        UNION ALL
        SELECT
        (SELECT
        re.id,
        re.`code`,
        re.refund_code,
@@ -482,10 +424,348 @@
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
            <choose>
                <when test="type3OrderIds != null and type3OrderIds.size() > 0">
                    AND re.vip_order_id IN
                    <foreach collection="type3OrderIds" item="id" open="(" separator="," close=")">
                        #{id}
                    </foreach>
                </when>
                <otherwise>
                    <if test="type3OrderIds != null">
                        AND 1 = 0
                    </if>
                </otherwise>
            </choose>
        </where>
        ORDER BY re.refund_time DESC
        LIMIT #{branchLimit})
        </if>
        ) o
        ORDER BY o.refund_time DESC
        LIMIT #{offset}, #{limit}
    </select>
    <!--
        退款总数(筛选逆反查版),与 getRefundListByOrderIds 同构,三分支 COUNT 可下推。
    -->
    <select id="countRefundListByOrderIds" resultType="long">
        SELECT SUM(cnt) FROM (
        (SELECT COUNT(*) AS cnt
        FROM t_charging_order_refund re
        <where>
            <if test="data.specialRefund != null and data.specialRefund">
                AND re.refund_title = '特殊退款处理'
            </if>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
            <choose>
                <when test="type1OrderIds != null and type1OrderIds.size() > 0">
                    AND re.charging_order_id IN
                    <foreach collection="type1OrderIds" item="id" open="(" separator="," close=")">
                        #{id}
                    </foreach>
                </when>
                <otherwise>
                    <if test="type1OrderIds != null">
                        AND 1 = 0
                    </if>
                </otherwise>
            </choose>
        </where>)
        <if test="data.specialRefund == null or !data.specialRefund">
        UNION ALL
        (SELECT COUNT(*) AS cnt
        FROM t_shopping_order_refund re
        <where>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
            <choose>
                <when test="type2OrderIds != null and type2OrderIds.size() > 0">
                    AND re.shopping_order_id IN
                    <foreach collection="type2OrderIds" item="id" open="(" separator="," close=")">
                        #{id}
                    </foreach>
                </when>
                <otherwise>
                    <if test="type2OrderIds != null">
                        AND 1 = 0
                    </if>
                </otherwise>
            </choose>
        </where>)
        UNION ALL
        (SELECT COUNT(*) AS cnt
        FROM t_vip_order_refund re
        <where>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
            <choose>
                <when test="type3OrderIds != null and type3OrderIds.size() > 0">
                    AND re.vip_order_id IN
                    <foreach collection="type3OrderIds" item="id" open="(" separator="," close=")">
                        #{id}
                    </foreach>
                </when>
                <otherwise>
                    <if test="type3OrderIds != null">
                        AND 1 = 0
                    </if>
                </otherwise>
            </choose>
        </where>)
        </if>
        ) t
    </select>
    <!--
        按支付流水号模糊匹配充电订单 id(逆反查第一步)。
        注意:前导通配符 LIKE '%x%' 无法走 recharge_serial_number 索引,MyCat 广播 50 张分片表全表扫描;
        匹配行一般极少(流水号近似唯一),结果集小,可接受。ORDER BY id 保证截断时结果确定性。
    -->
    <select id="listChargingOrderIdsBySerialNumber" resultType="long">
        SELECT id FROM t_charging_order
        WHERE recharge_serial_number LIKE CONCAT('%', #{serialNumber}, '%')
        ORDER BY id DESC
        LIMIT #{limit}
    </select>
    <!-- 按支付流水号模糊匹配商城订单 id(同前导通配符说明,广播 20 张分片表) -->
    <select id="listShoppingOrderIdsBySerialNumber" resultType="long">
        SELECT id FROM t_shopping_order
        WHERE serial_number LIKE CONCAT('%', #{serialNumber}, '%')
        ORDER BY id DESC
        LIMIT #{limit}
    </select>
    <!-- 按支付流水号模糊匹配会员订单 id(同前导通配符说明,广播 20 张分片表) -->
    <select id="listVipOrderIdsBySerialNumber" resultType="long">
        SELECT id FROM t_vip_order
        WHERE serial_number LIKE CONCAT('%', #{serialNumber}, '%')
        ORDER BY id DESC
        LIMIT #{limit}
    </select>
    <!-- 按站点匹配充电订单 id(逆反查第一步,site_id 走新增索引;ORDER BY id 保证截断时结果确定性) -->
    <select id="listChargingOrderIdsBySiteIds" resultType="long">
        SELECT id FROM t_charging_order
        WHERE site_id IN
        <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
            #{siteId}
        </foreach>
        ORDER BY id DESC
        LIMIT #{limit}
    </select>
    <!--
        退款列表(分片下推版)。
        三个 UNION 分支各自单表查询,分支内 ORDER BY + LIMIT 可被 MyCat 下推到每张分片表(每表最多取 offset+limit 行),
        代理层只归并三分支共 3×(offset+limit) 行再取页。相比旧版(90 张分片表全量拉回代理层排序)避免全量传输。
    -->
    <select id="getRefundListPage" resultType="com.ruoyi.order.api.model.TChargingOrderRefund">
        SELECT * FROM (
        (SELECT
        re.id,
        re.`code`,
        re.refund_code,
        re.refund_title,
        re.refund_reason,
        re.refund_amount,
        re.balance_refund_amount,
        re.third_refund_amount,
        re.refund_total_amount,
        re.refund_time,
        re.pay_type,
        re.pay_amount,
        re.refund_remark,
        re.charging_order_id AS order_id,
        1 AS type
        FROM t_charging_order_refund re
        <where>
            <if test="data.specialRefund != null and data.specialRefund">
                AND re.refund_title = '特殊退款处理'
            </if>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
        </where>
        ORDER BY re.refund_time DESC
        LIMIT #{branchLimit})
        <if test="data.specialRefund == null or !data.specialRefund">
        UNION ALL
        (SELECT
        re.id,
        re.`code`,
        re.refund_code,
        re.refund_title,
        re.refund_reason,
        re.refund_amount,
        0 AS balance_refund_amount,
        re.refund_amount AS third_refund_amount,
        re.refund_total_amount,
        re.refund_time,
        re.pay_type,
        re.pay_amount,
        re.refund_remark,
        re.shopping_order_id AS order_id,
        2 AS type
        FROM t_shopping_order_refund re
        <where>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
        </where>
        ORDER BY re.refund_time DESC
        LIMIT #{branchLimit})
        UNION ALL
        (SELECT
        re.id,
        re.`code`,
        re.refund_code,
        re.refund_title,
        re.refund_reason,
        re.refund_amount,
        0 AS balance_refund_amount,
        re.refund_amount AS third_refund_amount,
        re.refund_total_amount,
        re.refund_time,
        re.pay_type,
        re.pay_amount,
        re.refund_remark,
        re.vip_order_id AS order_id,
        3 AS type
        FROM t_vip_order_refund re
        <where>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
        </where>
        ORDER BY re.refund_time DESC
        LIMIT #{branchLimit})
        </if>
        ) o
        ORDER BY o.refund_time DESC
        LIMIT #{offset}, #{limit}
    </select>
    <!--
        退款总数(分片下推版)。三分支各自 COUNT(可下推到每张分片表),代理层只 SUM 三个数。
        旧版由分页拦截器生成 SELECT COUNT(*) FROM (90 表全量 UNION),MyCat 无法下推导致全量扫描。
    -->
    <select id="countRefundList" resultType="long">
        SELECT SUM(cnt) FROM (
        (SELECT COUNT(*) AS cnt
        FROM t_charging_order_refund re
        <where>
            <if test="data.specialRefund != null and data.specialRefund">
                AND re.refund_title = '特殊退款处理'
            </if>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
        </where>)
        <if test="data.specialRefund == null or !data.specialRefund">
        UNION ALL
        (SELECT COUNT(*) AS cnt
        FROM t_shopping_order_refund re
        <where>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
        </where>)
        UNION ALL
        (SELECT COUNT(*) AS cnt
        FROM t_vip_order_refund re
        <where>
            <if test="data.code != null and data.code != ''">
                AND re.code LIKE CONCAT('%', #{data.code}, '%')
            </if>
            <if test="data.refundCode != null and data.refundCode != ''">
                AND re.refund_code LIKE CONCAT('%', #{data.refundCode}, '%')
            </if>
            <if test="data.refundTime1 != null and data.refundTime1 != ''">
                AND re.refund_time &gt;= #{data.refundTime1}
            </if>
            <if test="data.refundTime2 != null and data.refundTime2 != ''">
                AND re.refund_time &lt;= #{data.refundTime2}
            </if>
        </where>)
        </if>
        ) t
    </select>
    <select id="chargingOrderGroup" resultType="com.ruoyi.common.core.dto.ChargingOrderGroup">
        SELECT SUM(tc.charging_capacity) as charging_capacity,tc.site_id
@@ -1343,26 +1623,8 @@
        b.start_soc as startSoc,
        b.end_soc as endSoc,
        b.`status`,
        b.end_mode as endMode,
        a.periodElectricPrice,
        a.periodServicePrice,
        a.jian,
        a.feng,
        a.ping,
        a.gu
        b.end_mode as endMode
        from t_charging_order b
        inner join (
            select
            charging_order_id,
            sum(period_electric_price) as periodElectricPrice,
            sum(period_service_price) as periodServicePrice,
            sum(CASE WHEN type = 1 THEN charging_capacity ELSE 0 END) as jian,
            sum(CASE WHEN type = 2 THEN charging_capacity ELSE 0 END) as feng,
            sum(CASE WHEN type = 3 THEN charging_capacity ELSE 0 END) as ping,
            sum(CASE WHEN type = 4 THEN charging_capacity ELSE 0 END) as gu
            from t_charging_order_accounting_strategy
            group by charging_order_id
        ) a on a.charging_order_id = b.id
        where b.del_flag = 0 and b.recharge_payment_status = 2
        <if test="null != req.code and req.code!=''">
            and b.code LIKE CONCAT('%',#{req.code},'%')
@@ -1405,6 +1667,23 @@
        </if>
        and b.start_time IS NOT NULL and b.end_time is not null
        order by b.start_time desc
    </select>
    <select id="chargingListAccountingSummary" resultType="map">
        select
        charging_order_id as orderId,
        sum(period_electric_price) as periodElectricPrice,
        sum(period_service_price) as periodServicePrice,
        sum(CASE WHEN type = 1 THEN charging_capacity ELSE 0 END) as jian,
        sum(CASE WHEN type = 2 THEN charging_capacity ELSE 0 END) as feng,
        sum(CASE WHEN type = 3 THEN charging_capacity ELSE 0 END) as ping,
        sum(CASE WHEN type = 4 THEN charging_capacity ELSE 0 END) as gu
        from t_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>
@@ -2346,8 +2625,11 @@
            CASE WHEN count(a.id) > 0 THEN (UNIX_TIMESTAMP(MAX(b.end_time)) - UNIX_TIMESTAMP(MAX(b.start_time))) ELSE 0 END as time,
            sum(a.charging_capacity) as total,
            sum(a.period_electric_price) as electronicMoney,
            sum(CASE WHEN b.order_source = 1 THEN a.period_service_price ELSE a.period_service_price * 0.8 END) as serviceMoney,
            sum(a.period_electric_price + (CASE WHEN b.order_source = 1 THEN a.period_service_price ELSE a.period_service_price * 0.8 END)) as income,
            sum(CASE
                    WHEN b.order_source = 1 THEN a.period_service_price
                    ELSE a.period_service_price * 0.8
                END) as serviceMoney,
            sum(a.period_electric_price + CASE WHEN b.order_source = 1 THEN a.period_service_price ELSE a.period_service_price * 0.8 END) as income,
            MAX(b.recharge_payment_type) as recharge_payment_type,
            MAX(b.is_whitelist) as is_whitelist,
            MAX(b.electrovalence) as electrovalence,
@@ -2420,25 +2702,11 @@
    <select id="chargingOrderShareIncomeByOrderIds" resultType="map">
        select
        s.charging_order_id as orderId,
        sum(
            IFNULL(s.channel_pay_amount, 0)
            - IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END)
            - IFNULL(s.share_amount, 0)
                * (IFNULL(s.channel_pay_amount, 0)
                    - IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END))
                / IFNULL(s.channel_pay_amount, 0)
        ) as platformIncome,
        sum(
            IFNULL(s.share_amount, 0)
            * (IFNULL(s.channel_pay_amount, 0)
                - IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END))
            / IFNULL(s.channel_pay_amount, 0)
        ) as partnerIncome
        sum(IFNULL(s.channel_pay_amount, 0) - IFNULL(s.share_amount, 0)) as platformIncome,
        sum(IFNULL(s.share_amount, 0)) as partnerIncome
        from `charging_pile_order`.t_charging_order_share_record s
        inner join `charging_pile_order`.t_charging_order o on o.id = s.charging_order_id
        where s.del_flag = 0 and s.charging_order_id is not null
        and IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END)
            &lt; IFNULL(s.channel_pay_amount, 0)
        <if test="orderIds != null and orderIds.size()>0">
            and s.charging_order_id in
            <foreach collection="orderIds" item="item" index="index" separator="," open="(" close=")">
@@ -2451,12 +2719,7 @@
    <select id="chargingOrderShareIncomeByPayChannel" resultType="map">
        select
        s.pay_channel as payChannel,
        sum(
            IFNULL(s.share_amount, 0)
            * (IFNULL(s.channel_pay_amount, 0)
                - IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END))
            / IFNULL(s.channel_pay_amount, 0)
        ) as shareAmount
        sum(IFNULL(s.share_amount, 0)) as shareAmount
        from t_charging_order_share_record s
        inner join t_charging_order o on s.charging_order_id = o.id
        where s.del_flag = 0
@@ -2464,8 +2727,6 @@
        and o.del_flag = 0
        and o.recharge_payment_status = 2
        and o.status = 5
        and IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END)
            &lt; IFNULL(s.channel_pay_amount, 0)
        <if test="sixBefore != null">
            and o.create_time &gt;= #{sixBefore}
        </if>
@@ -2480,25 +2741,11 @@
    <select id="chargingOrderShareIncomeSummaryByOrderIds" resultType="map">
        select
        sum(
            IFNULL(s.channel_pay_amount, 0)
            - IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END)
            - IFNULL(s.share_amount, 0)
                * (IFNULL(s.channel_pay_amount, 0)
                    - IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END))
                / IFNULL(s.channel_pay_amount, 0)
        ) as platformIncomeTotal,
        sum(
            IFNULL(s.share_amount, 0)
            * (IFNULL(s.channel_pay_amount, 0)
                - IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END))
            / IFNULL(s.channel_pay_amount, 0)
        ) as partnerIncomeTotal
        sum(IFNULL(s.channel_pay_amount, 0) - IFNULL(s.share_amount, 0)) as platformIncomeTotal,
        sum(IFNULL(s.share_amount, 0)) as partnerIncomeTotal
        from `charging_pile_order`.t_charging_order_share_record s
        inner join `charging_pile_order`.t_charging_order o on o.id = s.charging_order_id
        where s.del_flag = 0 and s.charging_order_id is not null
        and IFNULL(o.third_refund_amount, CASE WHEN o.pay_method = 3 THEN IFNULL(o.refund_amount, 0) ELSE 0 END)
            &lt; IFNULL(s.channel_pay_amount, 0)
        <if test="orderIds != null and orderIds.size()>0">
            and s.charging_order_id in
            <foreach collection="orderIds" item="item" index="index" separator="," open="(" close=")">
@@ -2568,21 +2815,19 @@
    </select>
    <select id="countOrdersByDate" resultType="com.ruoyi.order.vo.OrderCountByDate">
        SELECT DATE_FORMAT(create_time, '%m/%d') 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, '%m/%d')
        ORDER BY DATE(create_time, '%m/%d') ASC
          AND create_time &gt;= #{startTime}
          AND create_time &lt; #{endTime}
    </select>
@@ -2710,33 +2955,47 @@
    <select id="getAccountSettlementStatement" resultType="map">
        select
        aa.site_id as siteId,
        sum(aa.recharge_amount) as rechargeAmount,
        sum(aa.refund_amount) as refundAmount,
        sum(aa.serviceAmount) as serviceAmount
        from (
            select
            b.id as orderId,
            b.site_id,
            ifnull(b.payment_amount, 0) as recharge_amount,
            ifnull(c.refund_amount, 0) as refund_amount,
            sum(ifnull(a.period_service_price, 0)) as serviceAmount
            from t_charging_order_accounting_strategy a
            left join t_charging_order b on (a.charging_order_id = b.id)
            left join (
                select charging_order_id, sum(ifnull(refund_amount, 0)) as refund_amount
                from t_charging_order_refund
                where refund_status = 2
                group by charging_order_id
            ) c on b.id = c.charging_order_id
            where b.`status` = 5
              and b.del_flag = 0
              and b.order_source = 1
              and b.source_name = 'ICBC'
              and b.start_time between #{startTime} and #{endTime}
            group by orderId, site_id, recharge_amount, refund_amount
        ) as aa group by aa.site_id order by aa.site_id
        SELECT
            b.site_id AS siteId,
            SUM(CASE
                    WHEN sr.charging_order_id IS NOT NULL THEN sr.paid_amount
                    ELSE IFNULL(b.payment_amount, 0)
                END) AS rechargeAmount,
            SUM(IFNULL(r.refund_amount, 0)) AS refundAmount,
            SUM(CASE
                    WHEN sr.charging_order_id IS NOT NULL THEN sr.paid_service_amount
                    ELSE IFNULL(a.service_amount, 0)
                END) AS serviceAmount
        FROM t_charging_order b
        LEFT JOIN (
            SELECT charging_order_id,
                   SUM(IFNULL(period_service_price, 0)) AS service_amount
            FROM t_charging_order_accounting_strategy
            GROUP BY charging_order_id
        ) a ON a.charging_order_id = b.id
        LEFT JOIN (
            SELECT charging_order_id,
                   SUM(IFNULL(channel_pay_amount, 0)) AS paid_amount,
                   SUM(IFNULL(channel_service_amount, 0)) AS paid_service_amount
            FROM t_charging_order_share_record
            WHERE pay_channel = 'ICBC'
              AND del_flag = 0
            GROUP BY charging_order_id
        ) sr ON sr.charging_order_id = b.id
        LEFT JOIN (
            SELECT charging_order_id,
                   SUM(IFNULL(refund_amount, 0)) AS refund_amount
            FROM t_charging_order_refund
            WHERE refund_status = 2
            GROUP BY charging_order_id
        ) r ON r.charging_order_id = b.id
        WHERE b.status = 5
          AND b.del_flag = 0
          AND b.order_source = 1
          AND b.source_name = 'ICBC'
          AND b.start_time BETWEEN #{startTime} AND #{endTime}
        GROUP BY b.site_id
        ORDER BY b.site_id
    </select>
    <sql id="enterpriseChargingBaseWhere">
@@ -2744,13 +3003,13 @@
        AND toi.status IN (2, 3)
        AND tod.order_type = 1
        <if test="data.exactCompanyName != null and data.exactCompanyName != ''">
            AND toi.name = #{data.exactCompanyName}
            AND TRIM(toi.name) = TRIM(#{data.exactCompanyName})
        </if>
        <if test="(data.exactCompanyName == null or data.exactCompanyName == '') and data.companyName != null and data.companyName != ''">
            AND toi.name LIKE CONCAT('%', #{data.companyName}, '%')
            AND TRIM(toi.name) LIKE CONCAT('%', TRIM(#{data.companyName}), '%')
        </if>
        <if test="data.socialCreditCode != null and data.socialCreditCode != ''">
            AND IFNULL(toi.tax_identification_number, '') = #{data.socialCreditCode}
            AND IFNULL(TRIM(toi.tax_identification_number), '') = TRIM(#{data.socialCreditCode})
        </if>
        <if test="data.siteType != null">
            AND s.site_type = #{data.siteType}
@@ -2775,20 +3034,18 @@
            b.socialCreditCode,
            MAX(b.companyAddress) AS companyAddress,
            MAX(b.companyPhone) AS companyPhone,
            SUM(b.orderCount) AS chargingCount,
            COUNT(1) AS invoiceCount,
            SUM(CASE WHEN b.detailInvoiceAmount &gt; 0 THEN b.detailInvoiceAmount ELSE b.totalAmount END) AS invoiceAmount,
            MAX(b.latestChargingTime) AS latestChargingTime
        FROM (
            SELECT
                toi.id AS invoiceId,
                toi.name AS companyName,
                IFNULL(toi.tax_identification_number, '') AS socialCreditCode,
                TRIM(toi.name) AS companyName,
                IFNULL(TRIM(toi.tax_identification_number), '') AS socialCreditCode,
                MAX(toi.company_address) AS companyAddress,
                MAX(toi.company_phone) AS companyPhone,
                MAX(IFNULL(toi.total_amount, 0)) AS totalAmount,
                SUM(IFNULL(tod.invoice_amount, 0)) AS detailInvoiceAmount,
                COUNT(DISTINCT co.id) AS orderCount,
                MAX(co.start_time) AS latestChargingTime
            FROM t_order_invoice toi
            INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
@@ -2797,10 +3054,10 @@
            <where>
                <include refid="enterpriseChargingBaseWhere" />
            </where>
            GROUP BY toi.id, toi.name, toi.tax_identification_number
            GROUP BY toi.id, TRIM(toi.name), TRIM(toi.tax_identification_number)
        ) b
        GROUP BY b.companyName, b.socialCreditCode
        ORDER BY chargingCount DESC
        ORDER BY invoiceCount DESC
    </select>
    <select id="enterpriseTopSites" resultType="map">
@@ -2822,8 +3079,8 @@
    <select id="enterpriseTopSitesByCompanies" resultType="map">
        SELECT
            toi.name AS companyName,
            IFNULL(toi.tax_identification_number, '') AS socialCreditCode,
            TRIM(toi.name) AS companyName,
            IFNULL(TRIM(toi.tax_identification_number), '') AS socialCreditCode,
            s.name AS siteName,
            COUNT(DISTINCT co.id) AS counts
        FROM t_order_invoice toi
@@ -2833,12 +3090,12 @@
        <where>
            <include refid="enterpriseChargingBaseWhere" />
            AND s.name IS NOT NULL
            AND toi.name IN
            AND TRIM(toi.name) IN
            <foreach collection="companyNames" item="companyName" open="(" separator="," close=")">
                #{companyName}
            </foreach>
        </where>
        GROUP BY toi.name, toi.tax_identification_number, s.id, s.name
        GROUP BY TRIM(toi.name), TRIM(toi.tax_identification_number), s.id, s.name
    </select>
    <select id="enterpriseChargingTimes" resultType="java.time.LocalDateTime">
@@ -2856,8 +3113,8 @@
    <select id="enterpriseChargingTimesByCompanies" resultType="map">
        SELECT DISTINCT
            toi.name AS companyName,
            IFNULL(toi.tax_identification_number, '') AS socialCreditCode,
            TRIM(toi.name) AS companyName,
            IFNULL(TRIM(toi.tax_identification_number), '') AS socialCreditCode,
            co.start_time AS startTime
        FROM t_order_invoice toi
        INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
@@ -2866,16 +3123,64 @@
        <where>
            <include refid="enterpriseChargingBaseWhere" />
            AND co.start_time IS NOT NULL
            AND toi.name IN
            AND TRIM(toi.name) IN
            <foreach collection="companyNames" item="companyName" open="(" separator="," close=")">
                #{companyName}
            </foreach>
        </where>
        ORDER BY toi.name, co.start_time
        ORDER BY TRIM(toi.name), co.start_time
    </select>
    <sql id="enterpriseChargingDetailWhere">
        <include refid="enterpriseChargingBaseWhere" />
    <select id="enterpriseInvoiceIds" resultType="long">
        SELECT id
        FROM t_order_invoice
        <where>
            invoicing_object_type = 2
            AND status IN (2, 3)
            <if test="data.exactCompanyName != null and data.exactCompanyName != ''">
                AND TRIM(name) = TRIM(#{data.exactCompanyName})
            </if>
            <if test="(data.exactCompanyName == null or data.exactCompanyName == '') and data.companyName != null and data.companyName != ''">
                AND TRIM(name) LIKE CONCAT('%', TRIM(#{data.companyName}), '%')
            </if>
            <if test="data.socialCreditCode != null and data.socialCreditCode != ''">
                AND IFNULL(TRIM(tax_identification_number), '') = TRIM(#{data.socialCreditCode})
            </if>
        </where>
    </select>
    <select id="enterpriseInvoiceChargingDetails" resultType="com.ruoyi.order.api.model.TOrderInvoiceDetail">
        SELECT order_id AS orderId,
               electrovalence,
               service_charge AS serviceCharge
        FROM t_order_invoice_detail
        WHERE order_type = 1
          AND order_invoice_id IN
        <foreach collection="invoiceIds" item="invoiceId" open="(" separator="," close=")">
            #{invoiceId}
        </foreach>
    </select>
    <sql id="enterpriseChargingOrderWhere">
        co.id IN
        <foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
            #{orderId}
        </foreach>
        <if test="data.siteType != null">
            AND s.site_type = #{data.siteType}
        </if>
        <if test="data.partnerId != null">
            AND s.partner_id = #{data.partnerId}
        </if>
        <if test="data.siteId != null">
            AND co.site_id = #{data.siteId}
        </if>
        <if test="data.createTime1 != null">
            AND co.create_time &gt;= #{data.createTime1}
        </if>
        <if test="data.createTime2 != null">
            AND co.create_time &lt;= #{data.createTime2}
        </if>
        <if test="data.code != null and data.code != ''">
            AND co.code LIKE CONCAT('%', #{data.code}, '%')
        </if>
@@ -2908,6 +3213,23 @@
        </if>
    </sql>
    <select id="enterpriseChargingDetailCount" resultType="long">
        SELECT COUNT(*)
        FROM t_charging_order co
        <if test="data.siteType != null or data.partnerId != null or (data.partnerName != null and data.partnerName != '')">
            INNER JOIN charging_pile_service.t_site s ON s.id = co.site_id
        </if>
        <if test="data.partnerName != null and data.partnerName != ''">
            INNER JOIN charging_pile_service.t_partner p ON p.id = s.partner_id
        </if>
        <if test="data.phone != null and data.phone != ''">
            INNER JOIN charging_pile_account.t_app_user au ON au.id = co.app_user_id
        </if>
        <where>
            <include refid="enterpriseChargingOrderWhere" />
        </where>
    </select>
    <sql id="enterpriseChargingDetailSelect">
        SELECT
            co.id,
@@ -2928,16 +3250,12 @@
            au.phone AS phone,
            car.license_plate AS licensePlate,
            co.charging_capacity AS chargingCapacity,
            IFNULL(tod.electrovalence, 0) AS electrovalence,
            IFNULL(tod.service_charge, 0) AS serviceCharge,
            co.end_mode AS endMode,
            co.create_time AS createTime,
            co.start_time AS startTime,
            co.end_time AS endTime,
            co.pay_time AS payTime
        FROM t_order_invoice toi
        INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
        INNER JOIN t_charging_order co ON co.id = tod.order_id
        FROM t_charging_order co
        LEFT JOIN charging_pile_service.t_site s ON s.id = co.site_id
        LEFT JOIN charging_pile_service.t_partner p ON p.id = s.partner_id
        LEFT JOIN charging_pile_service.t_charging_pile cp ON cp.id = co.charging_pile_id
@@ -2949,17 +3267,10 @@
    <select id="enterpriseChargingDetail" resultType="com.ruoyi.order.dto.EnterpriseChargingDetailVO">
        <include refid="enterpriseChargingDetailSelect" />
        <where>
            <include refid="enterpriseChargingDetailWhere" />
            <include refid="enterpriseChargingOrderWhere" />
        </where>
        ORDER BY co.create_time DESC
    </select>
    <select id="enterpriseChargingDetailExport" resultType="com.ruoyi.order.dto.EnterpriseChargingDetailVO">
        <include refid="enterpriseChargingDetailSelect" />
        <where>
            <include refid="enterpriseChargingDetailWhere" />
        </where>
        ORDER BY co.create_time DESC
        LIMIT #{offset}, #{pageSize}
    </select>
    <select id="enterpriseChargingPeriodCounts" resultType="map">
@@ -3012,7 +3323,14 @@
    <select id="getLargeScreenSummary" resultType="java.util.Map">
        SELECT COUNT(DISTINCT charging_order.id) AS validOrderCount,
               COUNT(DISTINCT charging_order.app_user_id) AS chargingUserCount,
               (SELECT COUNT(DISTINCT user_count_order.app_user_id)
                FROM t_charging_order user_count_order
                <if test="siteIds != null and siteIds.size() > 0">
                    WHERE user_count_order.site_id IN
                    <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                        #{siteId}
                    </foreach>
                </if>) AS chargingUserCount,
               (SELECT COUNT(*)
                FROM charging_pile_account.t_app_user app_user
                WHERE app_user.del_flag = 0) AS registeredUserCount,
@@ -3080,4 +3398,343 @@
            AND site_id IN (${siteIdsCsv})
        </if>
    </select>
    <!-- ==================== 大屏预聚合表 t_large_screen_site_stat ==================== -->
    <!-- 任务用: 按月切片聚合。订单数为未删除、状态1-5;金额和电量保持已结束且已支付口径。 -->
    <select id="monthSliceAgg" resultType="java.util.Map">
        SELECT charging_order.site_id AS site_id,
               COUNT(DISTINCT charging_order.id) AS order_count,
               COUNT(DISTINCT charging_order.app_user_id) AS user_count,
               COALESCE(ROUND(SUM(CASE WHEN charging_order.status = 5
                   AND charging_order.recharge_payment_status = 2 THEN accounting.charging_capacity ELSE 0 END), 2), 0) AS capacity,
               COALESCE(ROUND(SUM(CASE WHEN charging_order.status = 5
                   AND charging_order.recharge_payment_status = 2 THEN accounting.period_electric_price ELSE 0 END), 2), 0) AS electric_fee,
               COALESCE(ROUND(SUM(CASE WHEN charging_order.status = 5
                   AND charging_order.recharge_payment_status = 2 AND charging_order.order_source IN (0, 1) THEN accounting.period_service_price
                   WHEN charging_order.status = 5
                   AND charging_order.recharge_payment_status = 2 THEN accounting.period_service_price * 0.8
                   ELSE 0 END), 2), 0) AS service_fee
        FROM t_charging_order charging_order
        LEFT JOIN t_charging_order_accounting_strategy accounting
               ON accounting.charging_order_id = charging_order.id
        WHERE charging_order.del_flag = 0
          AND charging_order.status IN (1, 2, 3, 4, 5)
          AND charging_order.create_time &gt;= #{startTime}
          AND charging_order.create_time &lt; #{endTime}
        GROUP BY charging_order.site_id
    </select>
    <!-- 任务用: 按月切片统计充电用户数(工作台口径: 所有订单的去重用户, 不区分状态/删除标记,
         与 countAllUserData 同定义; 按站点求和会有跨站重复计数) -->
    <select id="monthSliceUserAgg" resultType="java.util.Map">
        SELECT site_id AS site_id,
               COUNT(DISTINCT app_user_id) AS user_count
        FROM t_charging_order
        WHERE create_time &gt;= #{startTime}
          AND create_time &lt; #{endTime}
        GROUP BY site_id
    </select>
    <!-- 任务用: 按时间切片取 (site_id, app_user_id) 对(所有订单, 与工作台 countAllUserData 同口径) -->
    <select id="userSitePairsAgg" resultType="java.util.Map">
        SELECT DISTINCT site_id AS site_id, app_user_id AS app_user_id
        FROM t_charging_order
        WHERE create_time &gt;= #{startTime}
          AND create_time &lt; #{endTime}
          AND app_user_id IS NOT NULL
    </select>
    <!-- 任务用: 批量写入用户-站点对(幂等) -->
    <insert id="insertUserSitePairs">
        INSERT IGNORE INTO t_large_screen_user_site (site_id, app_user_id)
        VALUES
        <foreach collection="rows" item="row" separator=",">
            (#{row.siteId}, #{row.appUserId})
        </foreach>
    </insert>
    <!-- 接口用: 充电用户数精确去重(对表, 选中站点全局去重) -->
    <select id="userCountFromStat" resultType="java.lang.Long">
        SELECT COUNT(DISTINCT app_user_id)
        FROM t_large_screen_user_site
        WHERE site_id IN
        <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
            #{siteId}
        </foreach>
    </select>
    <!-- 任务用: 对表行数(启动回填判断) -->
    <select id="userSiteTableCount" resultType="java.lang.Long">
        SELECT COUNT(*) FROM t_large_screen_user_site
    </select>
    <!-- 任务用: 按日切片聚合, 口径与 getLargeScreenChargingPower 一致(无 status 过滤) -->
    <select id="daySliceAgg" resultType="java.util.Map">
        SELECT site_id AS site_id,
               COUNT(1) AS order_count,
               COALESCE(SUM(IFNULL(power, 0)), 0) AS total_power
        FROM t_charging_order
        WHERE del_flag = 0
          AND create_time &gt;= #{startTime}
          AND create_time &lt; #{endTime}
        GROUP BY site_id
    </select>
    <!-- 任务用: 注册用户总数 -->
    <select id="globalRegisteredUsers" resultType="java.lang.Long">
        SELECT COUNT(*)
        FROM charging_pile_account.t_app_user
        WHERE del_flag = 0
    </select>
    <!-- 任务用: 批量写入聚合行 -->
    <insert id="replaceSiteStatBatch">
        REPLACE INTO t_large_screen_site_stat
        (stat_type, period, site_id, order_count, user_count, capacity, electric_fee,
         service_fee, income, total_power, registered_user_count, update_time)
        VALUES
        <foreach collection="rows" item="row" separator=",">
            (#{row.statType}, #{row.period}, #{row.siteId}, #{row.orderCount}, #{row.userCount},
             #{row.capacity}, #{row.electricFee}, #{row.serviceFee}, #{row.income},
             #{row.totalPower}, #{row.registeredUserCount}, NOW())
        </foreach>
    </insert>
    <!-- 任务用: 表行数(启动回填判断) -->
    <select id="statTableCount" resultType="java.lang.Long">
        SELECT COUNT(*) FROM t_large_screen_site_stat
    </select>
    <!-- 接口用: 累计指标(M 行汇总) -->
    <select id="summaryFromStat" resultType="java.util.Map">
        SELECT COALESCE(SUM(order_count), 0) AS validOrderCount,
               COALESCE(SUM(user_count), 0) AS chargingUserCount,
               COALESCE(SUM(capacity), 0) AS totalChargingCapacity,
               COALESCE(SUM(electric_fee), 0) AS electricityFee,
               COALESCE(SUM(service_fee), 0) AS serviceFee,
               COALESCE(SUM(income), 0) AS totalIncome
        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>
    <!-- 接口用: 近 N 月收入趋势(M 行按 period 分组, period 为 yyyy-MM 字典序可比) -->
    <select id="incomeTrendFromStat" resultType="com.ruoyi.order.dto.SixChargingDto">
        SELECT period AS month,
               COALESCE(SUM(electric_fee), 0) AS electrovalence,
               COALESCE(SUM(service_fee), 0) AS service_charge
        FROM t_large_screen_site_stat
        WHERE stat_type = 'M'
          AND period &gt;= #{sixBefore}
        <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 period
    </select>
    <!-- 接口用: 日功率曲线(D 行按 period 分组, period 为 yyyy-MM-dd 字典序可比) -->
    <select id="powerFromStat" resultType="java.util.Map">
        SELECT period AS day,
               COALESCE(SUM(total_power), 0) AS total_power,
               COALESCE(SUM(order_count), 0) AS order_count
        FROM t_large_screen_site_stat
        WHERE stat_type = 'D'
          AND period &gt;= #{dayStart}
          AND period &lt; #{dayEnd}
        <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 period
    </select>
    <!-- 接口用: 注册用户数(G 行) -->
    <select id="registeredFromStat" resultType="java.lang.Long">
        SELECT registered_user_count
        FROM t_large_screen_site_stat
        WHERE stat_type = 'G'
          AND period = 'ALL'
          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>
    <!-- ==================== 加盟商看板聚合查询(SQL 聚合下推,替代全量拉订单到 JVM) ==================== -->
    <!-- 均为单表 GROUP BY,MyCat 下推到各分片表后代理合并少量行;过滤条件内联,不带 IPage 参数。 -->
    <!-- 注意: 本模块 mapUnderscoreToCamelCase=false,列别名显式使用驼峰。 -->
    <!-- 按 end_time 日聚合: 订单数/金额/服务费/电费/电量/功率/需求满足率/利用率 -->
    <select id="franchiseeDayStats" resultType="com.ruoyi.order.dto.FranchiseeDayStat">
        SELECT DATE(end_time)                       AS statDay,
               COUNT(*)                             AS orderCount,
               SUM(IFNULL(order_amount, 0))         AS orderAmount,
               SUM(COALESCE(order_amount, payment_amount)) AS orderAmountEffective,
               SUM(IFNULL(payment_amount, 0))       AS paymentAmount,
               SUM(IFNULL(service_charge, 0))       AS serviceFee,
               SUM(IFNULL(electrovalence, 0))       AS electrovalence,
               SUM(IFNULL(charging_capacity, 0))    AS capacity,
               SUM(IFNULL(charging_power, power))   AS totalPower,
               COUNT(IFNULL(charging_power, power)) AS powerCount,
               MAX(IFNULL(IFNULL(charging_power, power), 0)) AS maxPower,
               SUM(CASE WHEN `current` IS NOT NULL AND need_elec IS NOT NULL AND need_elec &gt; 0
                        THEN LEAST(ROUND(`current` * 100 / need_elec, 4), 100) ELSE 0 END) AS elecSatSum,
               SUM(CASE WHEN `current` IS NOT NULL AND need_elec IS NOT NULL AND need_elec &gt; 0
                        THEN 1 ELSE 0 END)          AS elecSatCount,
               SUM(CASE WHEN IFNULL(IFNULL(charging_power, power), 0) &gt; 0
                        THEN IFNULL(IFNULL(charging_power, power), 0) ELSE 0 END) AS utilPowerSum,
               SUM(CASE WHEN IFNULL(IFNULL(charging_power, power), 0) &gt; 0
                        THEN 1 ELSE 0 END)          AS utilPowerCount
        FROM t_charging_order
        WHERE del_flag = 0
          AND recharge_payment_status = 2
        <if test="siteIds != null and siteIds.size() > 0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
          AND end_time &gt;= #{start}
          AND end_time &lt; #{end}
        GROUP BY DATE(end_time)
    </select>
    <!-- 功率分布直方图(0-30/30-60/60-120/120-300/300kW以上) -->
    <select id="franchiseePowerBuckets" resultType="com.ruoyi.order.dto.FranchiseePowerBucket">
        SELECT CASE WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 30 THEN 0
                    WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 60 THEN 1
                    WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 120 THEN 2
                    WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 300 THEN 3
                    ELSE 4 END AS bucket,
               COUNT(*)        AS orderCount
        FROM t_charging_order
        WHERE del_flag = 0
          AND recharge_payment_status = 2
        <if test="siteIds != null and siteIds.size() > 0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
          AND end_time &gt;= #{start}
          AND end_time &lt; #{end}
        GROUP BY CASE WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 30 THEN 0
                      WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 60 THEN 1
                      WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 120 THEN 2
                      WHEN IFNULL(IFNULL(charging_power, power), 0) &lt; 300 THEN 3
                      ELSE 4 END
    </select>
    <!-- 尖峰平谷阶段电量: 按 charging_order_id 分片键路由,分块传入避免超大 IN -->
    <select id="franchiseePhaseStatsByOrderIds" resultType="com.ruoyi.order.dto.FranchiseePhaseStat">
        SELECT `type` AS type,
               SUM(IFNULL(charging_capacity, 0)) AS capacity
        FROM t_charging_order_accounting_strategy
        WHERE charging_order_id IN
        <foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
            #{orderId}
        </foreach>
        GROUP BY `type`
    </select>
    <!-- 站点+时间范围内订单 id 列表(仅 id 投影) -->
    <select id="franchiseeOrderIds" resultType="java.lang.Long">
        SELECT id
        FROM t_charging_order
        WHERE del_flag = 0
          AND recharge_payment_status = 2
        <if test="siteIds != null and siteIds.size() > 0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
          AND end_time &gt;= #{start}
          AND end_time &lt; #{end}
    </select>
    <!-- 用户维度聚合(仅 status=5 已结束订单) -->
    <select id="franchiseeUserAggs" resultType="com.ruoyi.order.dto.FranchiseeUserAgg">
        SELECT app_user_id              AS appUserId,
               app_user_car_id          AS appUserCarId,
               DATE(end_time)           AS statDay,
               COUNT(*)                 AS orderCount,
               SUM(IFNULL(charging_capacity, 0)) AS capacity,
               SUM(IFNULL(payment_amount, 0))     AS paymentAmount
        FROM t_charging_order
        WHERE del_flag = 0
          AND recharge_payment_status = 2
          AND status = 5
        <if test="siteIds != null and siteIds.size() > 0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
          AND end_time &gt;= #{start}
          AND end_time &lt; #{end}
        GROUP BY app_user_id, app_user_car_id, DATE(end_time)
    </select>
    <!-- 流量来源统计(仅 status=5 已结束订单,空值归"明星充电"由服务端处理) -->
    <select id="franchiseeTrafficStats" resultType="com.ruoyi.order.dto.FranchiseeSourceStat">
        SELECT IFNULL(tripartite_platform_name, '') AS source,
               COUNT(*)                             AS orderCount
        FROM t_charging_order
        WHERE del_flag = 0
          AND recharge_payment_status = 2
          AND status = 5
        <if test="siteIds != null and siteIds.size() > 0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
          AND end_time &gt;= #{start}
          AND end_time &lt; #{end}
        GROUP BY tripartite_platform_name
    </select>
    <!-- 按充电枪的需求满足率聚合(与 franchiseeDayStats 相同基础过滤,不含 status 过滤) -->
    <select id="franchiseeGunSatisfaction" resultType="com.ruoyi.order.dto.FranchiseeGunSat">
        SELECT charging_gun_id AS chargingGunId,
               SUM(CASE WHEN `current` IS NOT NULL AND need_elec IS NOT NULL AND need_elec &gt; 0
                        THEN LEAST(ROUND(`current` * 100 / need_elec, 4), 100) ELSE 0 END) AS satSum,
               SUM(CASE WHEN `current` IS NOT NULL AND need_elec IS NOT NULL AND need_elec &gt; 0
                        THEN 1 ELSE 0 END)          AS satCount
        FROM t_charging_order
        WHERE del_flag = 0
          AND recharge_payment_status = 2
        <if test="siteIds != null and siteIds.size() > 0">
            AND site_id IN
            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
                #{siteId}
            </foreach>
        </if>
          AND end_time &gt;= #{start}
          AND end_time &lt; #{end}
        GROUP BY charging_gun_id
    </select>
</mapper>