yeg
2026-09-07 279e85aa564967fb187ae9687b3c81a5eee5e74d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.battery.business.report;
 
import java.math.BigDecimal; import java.math.MathContext; import java.util.*;
import com.alibaba.fastjson2.*; import com.battery.business.domain.*; import com.battery.business.service.*;
import com.ruoyi.common.exception.ServiceException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;
 
/** 拼接报表按来源顺序平移循环号;统计只读取检测完成测试的当前有效循环记录。 */
@Service public class SpliceReportService {
 private final ITTestService tests; private final ITestDataQueryService data; private final SpliceReportRepository reports;
 public SpliceReportService(ITTestService t, ITestDataQueryService d, SpliceReportRepository r){tests=t;data=d;reports=r;}
 public record Candidate(SpliceReportRequest.Selection selection,String name,String type,long groupId,String group,String batteryNo,long startedAt){}
 public record Matrix(List<Map<String,Object>> segments,List<Integer> cycleNos){}
 public List<Candidate> sources(){ TTest q=new TTest(); q.setTestStatus("COMPLETED"); List<Candidate> out=new ArrayList<>(); for(TTest s:tests.selectTestList(q)){TTest t=tests.selectTestById(s.getTestId()); for(TTestBattery b:t.getBatteries()) out.add(candidate(t,b));} return out; }
 public Matrix preview(List<SpliceReportRequest.Selection> selections){
  if(selections==null||selections.size()<2||new HashSet<>(selections).size()!=selections.size()) throw new ServiceException("请选择至少两个不重复的检测完成测试电池");
  List<Map<String,Object>> segments=new ArrayList<>(); Set<Long> groups=new HashSet<>(); Set<String> batteries=new HashSet<>(); int offset=0; long group=0;
  for(var sel:selections){TTest t=tests.selectTestById(sel.testId()); if(t==null||!"COMPLETED".equals(t.getTestStatus())) throw new ServiceException("仅可选择检测完成测试"); TTestBattery b=t.getBatteries().stream().filter(x->sel.testBatteryId().equals(x.getTestBatteryId())).findFirst().orElseThrow(()->new ServiceException("电池不属于所选测试")); if(group==0)group=b.getGroupId(); if(group!=b.getGroupId()) throw new ServiceException("拼接测试必须属于同一电池组"); groups.add(b.getGroupId()); batteries.add(b.getBatteryNo());
   List<Map<String,Object>> rows=data.cycles(sel.testId()).stream().filter(r->Objects.equals(r.get("batteryNo"),b.getBatteryNo())).toList(); List<Integer> nos=rows.stream().map(this::cycle).filter(x->x>0).distinct().sorted().toList(); Map<String,Object> seg=new LinkedHashMap<>(); seg.put("source",candidate(t,b)); seg.put("offset",offset); seg.put("cycles",rows); seg.put("originalCycleNos",nos); seg.put("statistics",statistics(rows,nos)); segments.add(seg); offset += nos.size(); }
  if(batteries.size()==0) throw new ServiceException("未找到共同参与电池"); return new Matrix(segments,java.util.stream.IntStream.range(1,offset+1).boxed().toList()); }
 private Map<String,Object> statistics(List<Map<String,Object>> rows,List<Integer> nos){Map<String,Object> out=new LinkedHashMap<>(); for(int no:nos){var m=rows.stream().filter(r->cycle(r)==no).toList(); Map<String,Object> v=new LinkedHashMap<>(); if(m.size()==1){Map<String,Object> row=m.get(0); for(String k:List.of("chargeEnergy","dischargeEnergy","chargeCapacity","dischargeCapacity")) if(row.get(k)!=null)v.put(k,row.get(k)); Number c=num(v.get("chargeEnergy")),d=num(v.get("dischargeEnergy")); if(c!=null&&d!=null&&c.doubleValue()>0)v.put("energyEfficiency",BigDecimal.valueOf(d.doubleValue()).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(c.doubleValue()),MathContext.DECIMAL128));} out.put(Integer.toString(no),v);} return out;}
 private List<Map<String,Object>> dataStepRows(Map<String,Object> row){return List.of();}
 private Number num(Object x){return x instanceof Number?n((Number)x):null;} private Number n(Number x){return x;}
 @Transactional public Map<String,Object> create(SpliceReportRequest r,long uid,String user){Matrix m=preview(r.selections()); Map<String,Object> snap=new LinkedHashMap<>(); snap.put("name",r.name().trim());snap.put("description",r.description());snap.put("selections",r.selections());snap.put("segments",m.segments());snap.put("cycleNos",m.cycleNos());snap.put("settings",r.settings()); return get(reports.insert(r.name().trim(),JSON.toJSONString(snap),uid,user,System.currentTimeMillis()),null);}
 public Map<String,Object> get(long id,Integer version){var v=reports.get(id,version);Map<String,Object> x=JSON.parseObject(v.snapshotJson());x.put("id",id);x.put("versionNo",v.versionNo());x.put("creator",v.report().creator());x.put("createdAt",v.report().createdAt());x.put("operatorName",v.operatorName());x.put("versionCreatedAt",v.versionCreatedAt());x.put("changeSummary",v.changeSummary());return x;}
 @Transactional public Map<String,Object> edit(long id,SpliceReportRequest.Edit r,long uid,String user){reports.lock(id);var v=reports.get(id);if(v.versionNo()!=r.baseVersionNo())throw new ServiceException("报表已有新版本,请重新打开后编辑");var x=JSON.parseObject(v.snapshotJson());x.put("name",r.name().trim());x.put("description",r.description());x.put("settings",r.settings());reports.append(id,r.baseVersionNo()+1,r.name().trim(),x.toJSONString(),uid,user,r.changeSummary().trim());return get(id,null);}
 @Transactional public Map<String,Object> refresh(long id,int base,String summary,long uid,String user){reports.lock(id);var v=reports.get(id);if(v.versionNo()!=base)throw new ServiceException("报表已有新版本,请重新打开后编辑");var x=JSON.parseObject(v.snapshotJson());var selections=JSON.parseArray(x.getString("selections"),SpliceReportRequest.Selection.class);Matrix m=preview(selections);x.put("segments",m.segments());x.put("cycleNos",m.cycleNos());reports.append(id,base+1,x.getString("name"),x.toJSONString(),uid,user,"按最新来源生成:"+summary);return get(id,null);}
 public void delete(long id,long uid,String user){reports.lock(id);reports.delete(id,uid,user);} private Candidate candidate(TTest t,TTestBattery b){return new Candidate(new SpliceReportRequest.Selection(t.getTestId(),b.getTestBatteryId()),t.getTestName(),t.getTestTypeName(),b.getGroupId(),b.getGroupName(),b.getBatteryNo(),t.getStartedAtUtc()==null?0:t.getStartedAtUtc().getTime());} private int cycle(Map<String,Object> r){return r.get("cycleNo") instanceof Number n?n.intValue():0;}
}