From f54b0dff8157c7ef2547ac912d70cab63de50626 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 09 九月 2026 20:47:18 +0800
Subject: [PATCH] 按需读取化成旧报表摘要与循环曲线

---
 battery-business/src/main/java/com/battery/business/report/FormationReportRepository.java |   62 ++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 1 deletions(-)

diff --git a/battery-business/src/main/java/com/battery/business/report/FormationReportRepository.java b/battery-business/src/main/java/com/battery/business/report/FormationReportRepository.java
index 52dbef0..c837a10 100644
--- a/battery-business/src/main/java/com/battery/business/report/FormationReportRepository.java
+++ b/battery-business/src/main/java/com/battery/business/report/FormationReportRepository.java
@@ -1,11 +1,71 @@
 package com.battery.business.report;
 
 import javax.sql.DataSource;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import com.alibaba.fastjson2.JSON;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Repository;
 
 /** 化成身份与版本使用独立表,复用对比报表的事务内存储规则。 */
 @Repository
 public class FormationReportRepository extends ReportVersionRepository
 {
-    public FormationReportRepository(DataSource dataSource) { super(dataSource, "formation", "化成"); }
+    private final JdbcTemplate jdbc;
+    public FormationReportRepository(DataSource dataSource) {
+        super(dataSource, "formation", "化成"); jdbc = new JdbcTemplate(dataSource);
+    }
+
+    public record SourceSummary(Summary report, int versionNo, List<Map<String, Object>> sources) { }
+    public record CycleCurve(Map<String, Object> selection, Map<String, Object> curve) { }
+
+    /** 列表只从保存版本投影来源名称,禁止传输或反序列化测量快照。 */
+    public List<SourceSummary> listSources() {
+        return jdbc.query("""
+                SELECT r.report_id,r.report_name,r.creator_name,r.created_at_utc,v.version_no,
+                       JSON_EXTRACT(v.snapshot_json,'$.items[*].source')
+                FROM t_formation_report r JOIN t_formation_report_version v ON v.report_id=r.report_id
+                 AND v.version_no=(SELECT MAX(v2.version_no) FROM t_formation_report_version v2 WHERE v2.report_id=r.report_id)
+                ORDER BY r.created_at_utc DESC,r.report_id DESC
+                """, (rs,index)->new SourceSummary(new Summary(rs.getLong(1),rs.getString(2),rs.getString(3),rs.getTimestamp(4).getTime()),
+                rs.getInt(5), parseSources(rs.getString(6))));
+    }
+
+    /** 首屏投影不含任何循环曲线,旧快照也按相同路径读取,不重写历史 JSON。 */
+    public Version page(long id, Integer versionNo) {
+        return getProjection(id, versionNo, objectProjection("v.snapshot_json",
+                List.of("name","description","cycleNos","settings","calculatedValues","units","displayUnits","curveMode")));
+    }
+
+    /** 版本号由首屏查询固定,后续字段查询不会混入并发产生的新版本。 */
+    public List<Map<String, Object>> pageItems(long id, int versionNo) {
+        String path = "CONCAT('$.items[',j.item_index-1,']')";
+        String fields = List.of("source","cycleNos","cycles","metrics","businessFields","chargeSteps").stream()
+                .map(key->"'"+key+"',JSON_EXTRACT(v.snapshot_json,CONCAT("+path+",'."+key+"'))").collect(Collectors.joining(","));
+        return jdbc.query("SELECT JSON_OBJECT("+fields+") FROM t_formation_report_version v "
+                + "JOIN JSON_TABLE(v.snapshot_json,'$.items[*]' COLUMNS(item_index FOR ORDINALITY)) j ON TRUE "
+                + "WHERE v.report_id=? AND v.version_no=? ORDER BY j.item_index",
+                (rs,index)->JSON.parseObject(rs.getString(1)),id,versionNo);
+    }
+
+    /** 只投影指定保存循环,保留采样的原始顺序、空值、单位和独立来源身份。 */
+    public List<CycleCurve> cycleCurves(long id, int versionNo, int cycleNo) {
+        return jdbc.query("""
+                SELECT JSON_EXTRACT(v.snapshot_json,CONCAT('$.items[',j.item_index-1,'].source.selection')),
+                       JSON_EXTRACT(v.snapshot_json,CONCAT('$.items[',j.item_index-1,'].curves."',?,'"'))
+                FROM t_formation_report_version v
+                JOIN JSON_TABLE(v.snapshot_json,'$.items[*]' COLUMNS(item_index FOR ORDINALITY)) j ON TRUE
+                WHERE v.report_id=? AND v.version_no=? ORDER BY j.item_index
+                """, (rs,index)->new CycleCurve(JSON.parseObject(rs.getString(1)),JSON.parseObject(rs.getString(2))),cycleNo,id,versionNo);
+    }
+
+    private static String objectProjection(String document, List<String> keys) {
+        return "JSON_OBJECT("+keys.stream().map(key->"'"+key+"',JSON_EXTRACT("+document+",'$."+key+"')").collect(Collectors.joining(","))+")";
+    }
+
+    private static List<Map<String,Object>> parseSources(String json) {
+        if (json == null) return List.of();
+        return JSON.parseArray(json).stream().map(value->(Map<String,Object>)JSON.toJSON(value)).toList();
+    }
 }

--
Gitblit v1.7.1