From d7d4ae6cfb28adf7ef92f44332ff492f0cc7069c Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期五, 07 八月 2026 15:44:41 +0800
Subject: [PATCH] feat: 完善大屏与光储监控接口

---
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java              |   39 +++++----
 sql/20260807_energy_storage_monitoring_menu.sql                                                                  |   87 +++++++++++++++++++++
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java          |    3 
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java    |    7 +
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java                         |    4 +
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/LargeScreenController.java                    |   10 +-
 ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml                               |   53 ++++++++++--
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java |   16 ++++
 8 files changed, 186 insertions(+), 33 deletions(-)

diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
index c0724f3..926f9a7 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
@@ -309,6 +309,13 @@
 		return AjaxResult.success(chargeMonitoring);
 	}
 
+	@ResponseBody
+	@GetMapping("/screenChargeMonitoring/{siteId}")
+	@ApiOperation(value = "获取智慧充电大屏监控数据", tags = {"管理后台-智慧充电大屏"})
+	public AjaxResult<ChargeMonitoring> screenChargeMonitoring(@PathVariable Integer siteId){
+		return AjaxResult.success(chargingPileService.chargeMonitoringForScreen(siteId));
+	}
+
 	@RequiresPermissions(value = {"/chargingEquipmentMonitoring"}, logical = Logical.OR)
 	@ResponseBody
 	@GetMapping("/getChargingMonitoringSiteList")
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java
index 65b5ba6..41563bc 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java
@@ -101,6 +101,9 @@
 	 */
 	ChargeMonitoring chargeMonitoring(Integer siteId);
 
+	/** 智慧充电大屏监控数据,不按菜单权限过滤站点。 */
+	ChargeMonitoring chargeMonitoringForScreen(Integer siteId);
+
 	List<Site> getChargingMonitoringSiteList();
 
 	
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java
index f089706..5150148 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java
@@ -794,6 +794,22 @@
 	@Override
 	public ChargeMonitoring chargeMonitoring(Integer siteId) {
 		Set<Integer> siteIds = resolveChargingMonitoringSiteIds(siteId);
+		return buildChargeMonitoring(siteIds);
+	}
+
+	@Override
+	public ChargeMonitoring chargeMonitoringForScreen(Integer siteId) {
+		Set<Integer> siteIds;
+		if (siteId != null && siteId > 0) {
+			siteIds = Collections.singleton(siteId);
+		} else {
+			siteIds = siteService.list(new LambdaQueryWrapper<Site>()
+					.eq(Site::getDelFlag, 0)).stream().map(Site::getId).collect(Collectors.toSet());
+		}
+		return buildChargeMonitoring(siteIds);
+	}
+
+	private ChargeMonitoring buildChargeMonitoring(Set<Integer> siteIds) {
 		List<Site> sites = siteService.list(new LambdaQueryWrapper<Site>()
 				.in(Site::getId, siteIds)
 				.eq(Site::getDelFlag, 0));
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/LargeScreenController.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/LargeScreenController.java
index f4d2050..c2608cd 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/LargeScreenController.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/LargeScreenController.java
@@ -36,11 +36,11 @@
         return R.ok(chargingOrderService.getLargeScreenSummary(normalizeSiteIds(siteIds)));
     }
 
-    @ApiOperation(tags = {"大屏-收入趋势"}, value = "当年按月充电收入")
+    @ApiOperation(tags = {"大屏-收入趋势"}, value = "最近七日充电收入")
     @GetMapping("/incomeTrend")
     public R<List<SixChargingDto>> incomeTrend(@RequestParam("siteIds") List<Integer> siteIds) {
         return R.ok(chargingOrderService.getLargeScreenIncomeTrend(
-                normalizeSiteIds(siteIds), LocalDate.now().withDayOfYear(1)));
+                normalizeSiteIds(siteIds), LocalDate.now().minusDays(6)));
     }
 
     @ApiOperation(tags = {"大屏-停车场充电功率曲线图"},value = "停车场充电功率曲线图")
@@ -48,14 +48,14 @@
     public R<List<LargeChargingPowerVo>> getChargingPower(
             @RequestParam(value = "siteIds", required = false) List<Integer> siteIds){
         LocalDate today = LocalDate.now();
-        LocalDateTime startTime = today.minusDays(7).atStartOfDay();
-        LocalDateTime endTime = today.atStartOfDay();
+        LocalDateTime startTime = today.minusDays(6).atStartOfDay();
+        LocalDateTime endTime = today.plusDays(1).atStartOfDay();
         List<LargeChargingPowerVo> powerData = chargingOrderService.getLargeScreenChargingPower(
                 siteIds == null ? null : normalizeSiteIds(siteIds), startTime, endTime);
         Map<String, LargeChargingPowerVo> powerByDate = powerData.stream()
                 .collect(Collectors.toMap(LargeChargingPowerVo::getTime, Function.identity(), (left, right) -> left));
         ArrayList<LargeChargingPowerVo> largeChargingPowerVos = new ArrayList<>();
-        for (int count = 7; count > 0; count--) {
+        for (int count = 6; count >= 0; count--) {
             String time = today.minusDays(count).toString();
             LargeChargingPowerVo largeChargingPowerVo = powerByDate.getOrDefault(time, new LargeChargingPowerVo());
             largeChargingPowerVo.setTime(time);
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
index 282501f..2184f4d 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
@@ -322,6 +322,10 @@
     // 接口用: 近 N 月收入趋势(M 行按 period 分组)
     List<SixChargingDto> incomeTrendFromStat(@Param("siteIds") List<Integer> siteIds, @Param("sixBefore") String sixBefore);
 
+    List<SixChargingDto> incomeTrendFromOrders(@Param("siteIds") List<Integer> siteIds,
+                                               @Param("startTime") String startTime,
+                                               @Param("endTime") String endTime);
+
     // 接口用: 日功率曲线(D 行按 period 分组)
     List<Map<String, Object>> powerFromStat(@Param("siteIds") List<Integer> siteIds,
                                             @Param("dayStart") String dayStart, @Param("dayEnd") String dayEnd);
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
index 38a1afb..af8c9c9 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -7082,26 +7082,27 @@
         if (cached != null) {
             return cached;
         }
-        LocalDate currentMonth = LocalDate.now().withDayOfMonth(1);
+        LocalDate currentDay = LocalDate.now();
         List<SixChargingDto> result = new ArrayList<>();
         try {
-            String sixBeforeMonth = sixBefore.withDayOfMonth(1).format(LARGE_SCREEN_MONTH_FMT);
-            List<SixChargingDto> incomeList = this.baseMapper.incomeTrendFromStat(siteIds, sixBeforeMonth);
-            Map<String, SixChargingDto> incomeByMonth = new HashMap<>();
+            List<SixChargingDto> incomeList = this.baseMapper.incomeTrendFromOrders(siteIds,
+                    sixBefore.atStartOfDay().format(LARGE_SCREEN_SQL_FMT),
+                    currentDay.plusDays(1).atStartOfDay().format(LARGE_SCREEN_SQL_FMT));
+            Map<String, SixChargingDto> incomeByDay = new HashMap<>();
             if (incomeList != null) {
                 for (SixChargingDto income : incomeList) {
                     if (income != null && income.getMonth() != null) {
-                        incomeByMonth.put(income.getMonth(), income);
+                        incomeByDay.put(income.getMonth(), income);
                     }
                 }
             }
-            LocalDate month = sixBefore.withDayOfMonth(1);
-            while (!month.isAfter(currentMonth)) {
-                SixChargingDto income = incomeByMonth.get(month.format(LARGE_SCREEN_MONTH_FMT));
+            LocalDate day = sixBefore;
+            while (!day.isAfter(currentDay)) {
+                SixChargingDto income = incomeByDay.get(day.format(LARGE_SCREEN_DAY_FMT));
                 if (income == null) {
                     income = new SixChargingDto();
                 }
-                income.setMonth(String.format("%02d", month.getMonthValue()));
+                income.setMonth(day.format(LARGE_SCREEN_DAY_FMT));
                 if (income.getElectrovalence() == null) {
                     income.setElectrovalence(BigDecimal.ZERO);
                 }
@@ -7109,18 +7110,18 @@
                     income.setServiceCharge(BigDecimal.ZERO);
                 }
                 result.add(income);
-                month = month.plusMonths(1);
+                day = day.plusDays(1);
             }
         } catch (Exception e) {
             log.warn("大屏收入趋势读取预聚合表失败, siteIds={}, sixBefore={}", siteIds, sixBefore, e);
-            LocalDate month = sixBefore.withDayOfMonth(1);
-            while (!month.isAfter(currentMonth)) {
+            LocalDate day = sixBefore;
+            while (!day.isAfter(currentDay)) {
                 SixChargingDto income = new SixChargingDto();
-                income.setMonth(String.format("%02d", month.getMonthValue()));
+                income.setMonth(day.format(LARGE_SCREEN_DAY_FMT));
                 income.setElectrovalence(BigDecimal.ZERO);
                 income.setServiceCharge(BigDecimal.ZERO);
                 result.add(income);
-                month = month.plusMonths(1);
+                day = day.plusDays(1);
             }
         }
         redisService.setCacheObject(cacheKey, result, LARGE_SCREEN_CACHE_SECONDS, TimeUnit.SECONDS);
@@ -7333,9 +7334,11 @@
             stat.put("orderCount", decimalValue(row, "order_count"));
             stat.put("userCount", BigDecimal.ZERO);
             stat.put("capacity", BigDecimal.ZERO);
-            stat.put("electricFee", BigDecimal.ZERO);
-            stat.put("serviceFee", BigDecimal.ZERO);
-            stat.put("income", BigDecimal.ZERO);
+            BigDecimal electricFee = decimalValue(row, "electric_fee");
+            BigDecimal serviceFee = decimalValue(row, "service_fee");
+            stat.put("electricFee", electricFee);
+            stat.put("serviceFee", serviceFee);
+            stat.put("income", electricFee.add(serviceFee));
             stat.put("totalPower", decimalValue(row, "total_power"));
             stat.put("registeredUserCount", 0L);
             statRows.add(stat);
@@ -7804,7 +7807,7 @@
         List<LocalDate> dates = new ArrayList<>();
         List<Integer> counts = new ArrayList<>();
         LocalDate today = LocalDate.now();
-        for (int i = 7; i >= 1; i--) {//升序
+        for (int i = 6; i >= 0; i--) {//升序,最近七日(含当天)
             LocalDate day = today.minusDays(i);
             LocalDateTime dayStart = day.atStartOfDay();
             LocalDateTime dayEnd = day.plusDays(1).atStartOfDay();
diff --git a/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml b/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
index b7148c7..934b64d 100644
--- a/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
+++ b/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -3444,16 +3444,25 @@
         SELECT COUNT(*) FROM t_large_screen_user_site
     </select>
 
-    <!-- 任务用: 按日切片聚合, 口径与 getLargeScreenChargingPower 一致(无 status 过滤) -->
+    <!-- 任务用: 按日切片聚合,功率保持原口径;收入与月度切片一致。 -->
     <select id="daySliceAgg" resultType="java.util.Map">
-        SELECT site_id AS site_id,
+        SELECT charging_order.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
+               COALESCE(SUM(IFNULL(charging_order.power, 0)), 0) AS total_power,
+               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.create_time &gt;= #{startTime}
+          AND charging_order.create_time &lt; #{endTime}
+        GROUP BY charging_order.site_id
     </select>
 
     <!-- 任务用: 注册用户总数 -->
@@ -3499,13 +3508,13 @@
         </if>
     </select>
 
-    <!-- 接口用: 近 N 月收入趋势(M 行按 period 分组, period 为 yyyy-MM 字典序可比) -->
+    <!-- 接口用: 近 N 日收入趋势(D 行按 period 分组, period 为 yyyy-MM-dd 字典序可比) -->
     <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'
+        WHERE stat_type = 'D'
           AND period &gt;= #{sixBefore}
         <if test="siteIds != null and siteIds.size() > 0">
             AND site_id IN
@@ -3516,6 +3525,30 @@
         GROUP BY period
     </select>
 
+    <!-- 接口用: 最近七日收入,直接查询确保历史日切片升级后也能立即显示正确金额。 -->
+    <select id="incomeTrendFromOrders" resultType="com.ruoyi.order.dto.SixChargingDto">
+        SELECT DATE_FORMAT(charging_order.create_time, '%Y-%m-%d') AS month,
+               COALESCE(ROUND(SUM(accounting.period_electric_price), 2), 0) AS electrovalence,
+               COALESCE(ROUND(SUM(CASE WHEN charging_order.order_source IN (0, 1) THEN accounting.period_service_price
+                   ELSE accounting.period_service_price * 0.8 END), 2), 0) AS service_charge
+        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 = 5
+          AND charging_order.recharge_payment_status = 2
+          AND charging_order.create_time &gt;= #{startTime}
+          AND charging_order.create_time &lt; #{endTime}
+        <if test="siteIds != null and siteIds.size() > 0">
+            AND charging_order.site_id IN
+            <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
+                #{siteId}
+            </foreach>
+        </if>
+        GROUP BY DATE_FORMAT(charging_order.create_time, '%Y-%m-%d')
+        ORDER BY month
+    </select>
+
     <!-- 接口用: 日功率曲线(D 行按 period 分组, period 为 yyyy-MM-dd 字典序可比) -->
     <select id="powerFromStat" resultType="java.util.Map">
         SELECT period AS day,
diff --git a/sql/20260807_energy_storage_monitoring_menu.sql b/sql/20260807_energy_storage_monitoring_menu.sql
new file mode 100644
index 0000000..92bede8
--- /dev/null
+++ b/sql/20260807_energy_storage_monitoring_menu.sql
@@ -0,0 +1,87 @@
+-- 光储监控菜单调整:设备管理重命名,报表重命名,并将视频监控置于数据菜单首位。
+
+UPDATE sys_menu
+SET menu_name = '光储监控设备管理', update_time = NOW()
+WHERE parent_id = 0
+  AND menu_type = 'M'
+  AND (path = '/deviceManagement' OR perms = '/deviceManagement');
+
+SET @energy_data_id := (
+    SELECT menu_id
+    FROM sys_menu
+    WHERE parent_id = 0
+      AND menu_type = 'M'
+      AND (path = '/energyReport' OR perms = '/energyReport')
+    ORDER BY menu_id
+    LIMIT 1
+);
+
+UPDATE sys_menu
+SET menu_name = '光储监控数据', update_time = NOW()
+WHERE menu_id = @energy_data_id;
+
+INSERT INTO sys_menu
+    (menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
+     menu_type, visible, status, perms, icon, create_by, create_time, remark)
+SELECT '视频监控', @energy_data_id, 1, '/videoMonitor', 'videoMonitor', NULL, 1, 0,
+       'C', '0', 0, '/energyReport/videoMonitor', '#', 'admin', NOW(), '光储监控数据-视频监控'
+WHERE @energy_data_id IS NOT NULL
+  AND NOT EXISTS (
+      SELECT 1 FROM sys_menu
+      WHERE parent_id = @energy_data_id AND path = '/videoMonitor'
+  );
+
+SET @video_monitor_id := (
+    SELECT menu_id
+    FROM sys_menu
+    WHERE parent_id = @energy_data_id AND path = '/videoMonitor'
+    ORDER BY menu_id
+    LIMIT 1
+);
+
+UPDATE sys_menu
+SET menu_name = '视频监控', order_num = 1, component = 'videoMonitor', menu_type = 'C',
+    visible = '0', status = 0, perms = '/energyReport/videoMonitor', update_time = NOW()
+WHERE menu_id = @video_monitor_id;
+
+UPDATE sys_menu
+SET order_num = order_num + 1, update_time = NOW()
+WHERE parent_id = @energy_data_id
+  AND menu_id <> @video_monitor_id
+  AND order_num >= 1;
+
+-- 已拥有“光储监控数据”目录权限的角色同步获得视频监控权限。
+INSERT IGNORE INTO sys_role_menu (role_id, menu_id)
+SELECT role_id, @video_monitor_id
+FROM sys_role_menu
+WHERE menu_id = @energy_data_id;
+
+-- 光储监控设备管理的子菜单名称及顺序。
+SET @device_monitoring_id := (
+    SELECT menu_id FROM sys_menu
+    WHERE parent_id = 0
+      AND menu_type = 'M'
+      AND (path = '/deviceManagement' OR perms = '/deviceManagement')
+    ORDER BY menu_id
+    LIMIT 1
+);
+
+UPDATE sys_menu
+SET menu_name = '监控摄像头列表', order_num = 1, update_time = NOW()
+WHERE parent_id = @device_monitoring_id AND path = '/deviceManagement/list';
+
+UPDATE sys_menu
+SET menu_name = '光伏电站管理', order_num = 2, update_time = NOW()
+WHERE parent_id = @device_monitoring_id AND path = '/deviceManagement/photovoltaicStation/list';
+
+UPDATE sys_menu
+SET menu_name = '储能电站管理', order_num = 3, update_time = NOW()
+WHERE parent_id = @device_monitoring_id AND path = '/deviceManagement/energyStorage/list';
+
+UPDATE sys_menu
+SET menu_name = '光伏逆变器管理', order_num = 4, update_time = NOW()
+WHERE parent_id = @device_monitoring_id AND path = '/deviceManagement/photovoltaicInverter/list';
+
+UPDATE sys_menu
+SET menu_name = '储能能量链管理', order_num = 5, update_time = NOW()
+WHERE parent_id = @device_monitoring_id AND path = '/deviceManagement/energyChain/list';

--
Gitblit v1.7.1