yangyj hai 1 ano
pai
achega
ecd15fd529

+ 52 - 1
blade-common/src/main/java/org/springblade/common/utils/BaseUtils.java

@@ -10,7 +10,7 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
 import java.security.MessageDigest;
-import java.time.LocalDate;
+import java.time.*;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.regex.Matcher;
@@ -537,5 +537,56 @@ public static List<Object> obj2List(Object obj) {
         return Optional.ofNullable(date).orElse(LocalDate.now()).format(chineseDateFm);
    }
 
+    public  static long  getTimeMs(int periodYear,int periodMonth ){
+        LocalDateTime localDateTime = LocalDateTime.of(periodYear, periodMonth, 1, 0, 0, 0);
+        ZoneId zoneId = ZoneId.systemDefault(); // 使用系统默认时区
+        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
+        return zonedDateTime.toInstant().toEpochMilli();
+    }
+
+    public static LocalDateTime toLdt(long millis) {
+        Instant instant = Instant.ofEpochMilli(millis);
+        ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
+        return zonedDateTime.toLocalDateTime();
+    }
+
+    public static int dateInt(int periodYear,int periodMonth){
+        return   periodYear*100+periodMonth;
+    }
+
+
+
+    public static List<Integer> getTickUnit(int min, int max){
+        int a1 = min / 100; // 得到最小年份
+        int a2 = max / 100; // 得到最大年份
+        int b1 = min % 100; // 得到最小月份
+        int b2 = max % 100; // 得到最大月份
+        // 确保月份在 1 到 12 之间
+        if (b1 == 0) { b1 = 1; a1--; }
+        if (b2 == 0) { b2 = 12; a2--; }
+        int finalA = a1;
+        int finalB = b1;
+        int finalA1 = a2;
+        int finalB1 = b2;
+        return IntStream.rangeClosed(a1, a2)
+                .boxed()
+                .flatMap(year -> {
+                    int startMonth = (year == finalA) ? finalB : 1;
+                    int endMonth = (year == finalA1) ? finalB1 : 12;
+                    return IntStream.rangeClosed(startMonth, endMonth)
+                            .boxed()
+                            .map(month -> dateInt(year, month));
+                })
+                .collect(Collectors.toList());
+    }
+
+
+/*
+    public static void main(String[] args) {
+        getTickUnit(202401,202410).forEach(System.out::println);
+    }
+*/
+
+
 
 }

+ 1 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ChapterSchedule.java

@@ -14,6 +14,7 @@ import java.math.BigDecimal;
 public class ChapterSchedule {
      private String formNumber;
      private String formName;
+     private Integer year;
     private BigDecimal one=BigDecimal.ZERO;
     private BigDecimal two=BigDecimal.ZERO;
     private BigDecimal three=BigDecimal.ZERO;

+ 20 - 1
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/Payment.java

@@ -1,9 +1,12 @@
 package org.springblade.manager.vo;
 
 import lombok.Data;
+import org.springblade.common.utils.BaseUtils;
 
 import java.math.BigDecimal;
-import java.time.LocalDate;
+import java.time.*;
+import java.util.Calendar;
+import java.util.Date;
 
 /**
  * @author yangyj
@@ -49,6 +52,10 @@ public class Payment {
     private Long periodId;
     /**业务日期*/
     private LocalDate businessDate;
+    /**计量期年*/
+    private int periodYear;
+    /**计量期月*/
+    private int periodMonth;
     public BigDecimal getMoneyAsBigDecimal() {
         try {
             return new BigDecimal(getMoney());
@@ -61,4 +68,16 @@ public class Payment {
         return this.meterId.toString()+this.formId;
     }
 
+    /*获取时间戳*/
+    public long  getTimeMs(){
+       return BaseUtils.getTimeMs(periodYear,periodMonth);
+    }
+    /*获取年月映射*/
+    public int dateInt(){
+      return   this.periodYear*100+periodMonth;
+    }
+
+
+
+
 }

+ 48 - 43
blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java

@@ -34,10 +34,12 @@ import org.jfree.chart.axis.*;
 import org.jfree.chart.plot.*;
 import org.jfree.chart.renderer.category.BarRenderer;
 import org.jfree.chart.renderer.category.LineAndShapeRenderer;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
 import org.jfree.chart.renderer.xy.XYSplineRenderer;
 import org.jfree.chart.title.TextTitle;
 import org.jfree.chart.ui.RectangleEdge;
+import org.jfree.chart.ui.TextAnchor;
 import org.jfree.data.category.CategoryDataset;
 import org.jfree.data.category.DefaultCategoryDataset;
 import org.jfree.data.xy.XYSeries;
@@ -80,6 +82,9 @@ import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.*;
 import java.util.List;
 import java.util.concurrent.ThreadLocalRandom;
@@ -1271,11 +1276,9 @@ public class FormulaUtils {
         return null;
     }
 
-    public static String  chapterScheduleChartUrl( double[] actual ,double[] planned){
-        /*CategoryDataset dataset = createDataset(actualProgress,plannedProgress);
-        JFreeChart chart = createChart(dataset);*/
+    public static String  chapterScheduleChartUrl( LinkedHashMap<Long,Double> actualMap, LinkedHashMap<Long,Double> plannedMap,int startYear,int endYear){
           try {
-              JFreeChart chart =chartTest(actual,planned);
+              JFreeChart chart =chartTest(actualMap,plannedMap, startYear, endYear);
               String path= getSysLocalFileUrl() + "/pdf//"+SnowFlakeUtil.getId()+".png";
             ChartUtils.saveChartAsPNG(new File(path), chart, 800, 600);
             return path;
@@ -1286,7 +1289,7 @@ public class FormulaUtils {
     }
 
 
-   public static JFreeChart  chartTest(double[] actualProgressData ,double[] plannedProgressData) throws IOException {
+   public static JFreeChart  chartTest2(double[] actualProgressData ,double[] plannedProgressData) throws IOException {
        // 创建数据集
        XYSeries actualProgress = new XYSeries("实际进度");
        XYSeries plannedProgress = new XYSeries("计划进度");
@@ -1330,13 +1333,6 @@ public class FormulaUtils {
        renderer.setSeriesPaint(1, Color.GREEN);
        plot.setRenderer(renderer);
 
-/*       // 设置主X轴
-       NumberAxis domainAxis = new NumberAxis("日期进度 (%)");
-       domainAxis.setRange(0, 100);
-       domainAxis.setTickUnit(new NumberTickUnit(10));
-       domainAxis.setTickLabelFont(font);
-       domainAxis.setLabelFont(font);*/
-
 
        // 设置顶部的月份轴
       /* String[] months = {"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};
@@ -1369,58 +1365,67 @@ public class FormulaUtils {
 
        return chart;
     }
-    public static JFreeChart chartTest2(double[] actualProgressData, double[] plannedProgressData) {
-        // 创建数据集
-        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
-        String[] months = new String[4 * 12];
-        for (int i = 2023; i <= 2026; i++) {
-            for (int n = 1; n <= 12; n++) {
-                int index = (i - 2023) * 12 + n - 1;
-                months[index] = i + "年" + n + "月";
-            }
-        }
+    public static JFreeChart chartTest(LinkedHashMap<Long,Double> actualMap, LinkedHashMap<Long,Double> plannedMap,int startYear,int endYear) {
+        // 创建完整的数据集
+        XYSeriesCollection dataset = new XYSeriesCollection();
 
-        for (int i = 0; i < months.length; i++) {
-            dataset.addValue(actualProgressData.length-1>i?actualProgressData[i]:0, "实际进度", months[i]);
-            dataset.addValue(plannedProgressData.length-1>i?plannedProgressData[i]:0, "计划进度", months[i]);
-        }
+        // 创建日期范围
+        long startDate=BaseUtils.getTimeMs(startYear,1);
+
+
+        long endDate = BaseUtils.getTimeMs(endYear,12);
+
+        // 初始化数据系列
+        XYSeries actualSeries = new XYSeries("实际进度");
+        XYSeries plannedSeries = new XYSeries("计划进度");
+
+        // 填充数据系列
+        actualMap.forEach(actualSeries::add);
+        plannedMap.forEach(plannedSeries::add);
+        dataset.addSeries(actualSeries);
+        dataset.addSeries(plannedSeries);
 
         // 创建图表
-        JFreeChart chart = ChartFactory.createLineChart(
-                "施工进度对比图", // 标题
-                "日期进度 (%)", // X轴标签
-                "完成量 (%)", // Y轴标签
-                dataset // 数据集
-        );
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                "施工进度对比图",
+                "时间",
+                "完成量 (%)",
+                dataset,
+                true,
+                true,
+                false);
 
         // 设置中文字体以避免乱码
         Font font = new Font("宋体", Font.PLAIN, 12);
         chart.getTitle().setFont(font);
         chart.getLegend().setItemFont(font);
 
-        CategoryPlot plot = (CategoryPlot) chart.getPlot();
+        XYPlot plot = (XYPlot) chart.getPlot();
         plot.setDomainGridlinesVisible(true);
         plot.setRangeGridlinesVisible(true);
         plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
         plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
         plot.setBackgroundPaint(Color.WHITE);
 
-        LineAndShapeRenderer renderer = new LineAndShapeRenderer();
+        XYItemRenderer renderer = new XYSplineRenderer();
         renderer.setSeriesPaint(0, Color.BLUE);
         renderer.setSeriesPaint(1, Color.GREEN);
         plot.setRenderer(renderer);
 
-        // 设置顶部的月份轴
-        CategoryAxis monthAxis = new CategoryAxis("月份");
+        // 设置 DateAxis
+        DateAxis monthAxis = (DateAxis) plot.getDomainAxis();
+        monthAxis.setDateFormatOverride(new SimpleDateFormat("yyyy年MM月"));
         monthAxis.setTickLabelFont(font);
         monthAxis.setLabelFont(font);
-        monthAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 设置标签倾斜45度
-        monthAxis.setMaximumCategoryLabelWidthRatio(1.0f); // 确保所有标签显示
-        plot.setDomainAxis(monthAxis);
+        monthAxis.setLowerBound(startDate);
+        monthAxis.setUpperBound(endDate);
+        // 确保每个月都有一个标签
+        monthAxis.setTickUnit(new DateTickUnit(DateTickUnitType.MONTH,1));
+        monthAxis.setVerticalTickLabels(true);
 
         // 设置Y轴的范围
         NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
-        rangeAxis.setRange(0, 100); // Y轴从0到100
+        rangeAxis.setRange(0, 100);
         rangeAxis.setTickUnit(new NumberTickUnit(10));
         rangeAxis.setLabelFont(font);
         rangeAxis.setTickLabelFont(font);
@@ -1428,10 +1433,10 @@ public class FormulaUtils {
         return chart;
     }
     public static void main(String[] args) throws IOException {
-        double[] actualProgress = {10, 15, 18, 27, 35, 48};
-        double[] plannedProgress = {10, 15, 20, 25, 30, 35};
+        LinkedHashMap<Long,Double> actualProgress = new LinkedHashMap<>();
+        LinkedHashMap<Long,Double> plannedProgress = new LinkedHashMap<>();
 
-        JFreeChart chart = chartTest2(actualProgress,plannedProgress);
+        JFreeChart chart = chartTest(actualProgress,plannedProgress,2023,2025);
 /*        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
             BufferedImage bufferedImage = chart.createBufferedImage(800, 600);
             ImageIO.write(bufferedImage, "png", out);

+ 205 - 7
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/ExecutorMeter.java

@@ -26,6 +26,7 @@ import org.springframework.beans.BeanUtils;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -45,7 +46,7 @@ import java.util.stream.IntStream;
 public class ExecutorMeter extends FormulaExecutor {
     private Function<Long, List<MeterApply>> meterApplyFc;
     private Function<Long, List<StartPayForm>> stayPayFormFc;
-    private  BiFunction<String,String, List<ChapterSchedule>> chapterScheduleFc;
+    private Function<String, List<ChapterSchedule>> chapterScheduleFc;
 
     private ElementWriter elementWriter;
     /**执行链*/
@@ -1011,7 +1012,7 @@ public class ExecutorMeter extends FormulaExecutor {
                      payItemZj.add(new InterimPaymentCertificate("扣回材料设备垫付款"));
                       blj=new InterimPaymentCertificate("保留金",MINUS_ONE);
                      payItemZj.add(blj);
-                     InterimPaymentCertificate thblj=new InterimPaymentCertificate("退还保留金");
+                     InterimPaymentCertificate thblj=new InterimPaymentCertificate("返回保留金");
                      thblj.setNoApply(1);
                      payItemZj.add(thblj);
                      InterimPaymentCertificate sjzf=new InterimPaymentCertificate("实际支付",true);
@@ -1040,6 +1041,7 @@ public class ExecutorMeter extends FormulaExecutor {
                      RebateIncentiveAdvPay rebateIncentiveAdvPay = new RebateIncentiveAdvPay();
                      for (InterimPaymentCertificate certificate : dataList) {
                          InterimPayCertificateItem ic=  currentMap.getOrDefault(payItemZj.contains(certificate)?certificate.getChapterSeq():certificate.getFormName(),new InterimPayCertificateItem());
+                         InterimPayCertificateItem icPre= previousMap.getOrDefault(payItemZj.contains(certificate)?certificate.getChapterSeq():certificate.getFormName(),new InterimPayCertificateItem());
                          if("小计".equals(certificate.getChapterSeq())){
                              /*本期扣回动员预付款*/
                              BaseInfo baseInfo = tec.meterInfo.getBaseInfo();
@@ -1087,8 +1089,12 @@ public class ExecutorMeter extends FormulaExecutor {
                              certificate.setCurrentPeriodEndPay(rebateIncentiveAdvPay.getEndPay());
                              certificate.setCurrentPeriodPay(rebateIncentiveAdvPay.getCurrentPay());
                              certificate.setPreviousPeriodEndPay(rebateIncentiveAdvPay.getPreviousPay());
-                         }else if("退还保留金".equals(certificate.getChapterSeq())){
+                         }else if("返回保留金".equals(certificate.getChapterSeq())){
                              certificate.setCurrentPeriodPay(ic.getCurrentPeriodPay());
+                             ic.setPreviousPeriodEndPay(icPre.getCurrentPeriodEndPay());
+                             ic.setCurrentPeriodEndPay(addFc.apply(ic.getCurrentPeriodPay(),ic.getPreviousPeriodEndPay()));
+                             certificate.setPreviousPeriodEndPay(ic.getPreviousPeriodEndPay());
+                             certificate.setCurrentPeriodEndPay(ic.getCurrentPeriodEndPay());
                          }
                          BeanUtils.copyProperties(certificate,ic);
                          /*同时兼容几个表后,支付章名称和章节号有点混乱,需要注意纠正*/
@@ -1467,7 +1473,7 @@ public class ExecutorMeter extends FormulaExecutor {
 
     @Data
     @EqualsAndHashCode(callSuper = true)
-    public  class ConSchChapter extends   BaseSpecial<ConstructionSchedule> implements Special{
+    public  class ConSchChapter2 extends   BaseSpecial<ConstructionSchedule> implements Special{
 
         @Override
         public boolean ready() {
@@ -1478,7 +1484,7 @@ public class ExecutorMeter extends FormulaExecutor {
         public void parse() {
             builderFormDatas(ConstructionSchedule.class);
 
-            List<ChapterSchedule> chapterSchedules=chapterScheduleFc.apply(tec.periodInfo.getYear(),tec.getContractId().toString());
+            List<ChapterSchedule> chapterSchedules=chapterScheduleFc.apply(tec.getContractId().toString());
             /*支付信息根据章节、月份分组*/
             List<InventoryForm> inventoryForms = tec.meterInfo.getInventoryForms();
             List<InventoryForm> chapters = tec.meterInfo.getChapter();
@@ -1519,7 +1525,7 @@ public class ExecutorMeter extends FormulaExecutor {
                 cs.setCurrentPayPercent(ratioFc.apply(cs.getCurrentPeriodPay(),cs.getChangeMoney()));
                 /* 本期末累计支付金额占合同比*/
                 cs.setPayPercent(ratioFc.apply(cs.getCurrentPeriodEndPay(),cs.getChangeMoney()));
-                /**本期末占合合同金额 */
+                /*本期末占合合同金额 */
                 cs.setPrePayPercent(ratioFc.apply(cs.getCurrentPeriodEndPay(),cs.getContractMoney()));
                 /*变更金额*/
                 cs.setChangeMoneyAll(subtractFc.apply(cs.getChangeMoney(),cs.getContractMoney()));
@@ -1576,7 +1582,199 @@ public class ExecutorMeter extends FormulaExecutor {
                         FileOutputStream fos = new FileOutputStream("C:/Users/yangyj/Desktop/Swap_space/poi_statistics2.png");
                         fos.write(chartBytes);
                         BladeFile chartFile= tec.getNewIOSSClient().updateFile(chartBytes, ConstructionSchedule.TBN+SnowFlakeUtil.getId()+".png");*/
-                        String path=FormulaUtils.chapterScheduleChartUrl(actual,planned);
+                        String path=FormulaUtils.chapterScheduleChartUrl(null,null,2023,2024);
+                        BladeFile chartFile= tec.getNewIOSSClient().uploadFile( ConstructionSchedule.TBN+ SnowFlakeUtil.getId() + ".png",path);
+                        /*施工进度图*/
+                        FormulaUtils.elementFindByCode(fdm, ConstructionSchedule.TBN + ":key_29").ifPresent(t -> {
+                            elementWriter.write(t, chartFile.getLink());
+                        });
+                    }catch (Exception e){
+                        e.printStackTrace();
+                    }
+                }
+            }catch (Exception e){
+                StaticLog.error(e.getMessage());
+            }
+
+            /* 合同概要*/
+            FormulaUtils.elementFindByCode(fdm,ConstructionSchedule.TBN+":key_24").ifPresent(t->{
+                /*合同时长*/
+                String contractDay=CustomFunction.join(CustomFunction.daysPassed(baseInfo.getStartDatePlan(),baseInfo.getEndDatePlan()),"").toString();
+                /*总时长*/
+                String totalDay=CustomFunction.join(CustomFunction.daysPassed(baseInfo.getStartDate(),baseInfo.getEndDate()),"").toString();
+                /*延长时间*/
+                int extended=BaseUtils.obj2IntegerZero(contractDay)-BaseUtils.obj2IntegerZero(totalDay);
+                /*已过去*/
+                String passDay=CustomFunction.join(CustomFunction.daysPassed(baseInfo.getStartDate(), LocalDate.now()),"").toString();
+
+                BigDecimal provisionalSum=tec.meterInfo.getInventoryForms().stream().filter(e->"D".equals(e.getFormNumber())).map(e->BaseUtils.str2BigDecimal(e.getBidPrice())).reduce(BigDecimal.ZERO,BigDecimal::add);
+                BigDecimal BOQAmount=tec.meterInfo.getInventoryForms().stream().filter(e->!"D".equals(e.getFormNumber())).map(e->BaseUtils.str2BigDecimal(e.getBidPrice())).reduce(BigDecimal.ZERO,BigDecimal::add);
+                baseInfo.setProvisionalSum(StringUtils.number2String(provisionalSum,2));
+                baseInfo.setBOQAmount(StringUtils.number2String(BOQAmount,2));
+                BigDecimal changeTokenTotal=tec.meterInfo.getChangeTokenListMap().values().stream().flatMap(Collection::stream).map(ChangeToken::getTotalChangeMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
+                double totalMoney = BaseUtils.obj2DoubleZero(baseInfo.getContractAmount())+BaseUtils.obj2DoubleZero(baseInfo.getProvisionalSum())+BaseUtils.obj2DoubleZero(baseInfo.getBOQAmount())+BaseUtils.obj2DoubleZero(changeTokenTotal);
+                String brief="开工日期:"+baseInfo.getStartDatePlan()+" 始算工期日:"+baseInfo.getStartDate()
+                        +" 合同完成日期:"+baseInfo.getEndDatePlan()+" 合同期限"+contractDay+"天 时间延长"+extended+"天 修改后合同期限"+ totalDay
+                        +"天(即至"+baseInfo.getEndDate()+")"
+                        + "\n 合同总价"+CustomFunction.xN(baseInfo.getContractAmount(),0.0001)+"万元、暂定金"
+                        +CustomFunction.xN(baseInfo.getProvisionalSum(),0.0001)+"万元、工程量清单金额"
+                        +CustomFunction.xN(baseInfo.getBOQAmount(),0.0001)+"万元、工程量变更("+CustomFunction.xN(changeTokenTotal,0.0001)+")万元、估计最终金额"+CustomFunction.xN(totalMoney,0.0001)+"万元,时间已过"
+                        +passDay+"天,占合同工期"+StringUtils.number2String(ratioFc.apply(passDay,totalDay),2)+"%";
+                elementWriter.write(t,brief);
+            });
+
+            /*内容输出*/
+            putOut(ConstructionSchedule.class);
+
+        }
+    }
+    @Data
+    @EqualsAndHashCode(callSuper = true)
+    public  class ConSchChapter extends   BaseSpecial<ConstructionSchedule> implements Special{
+
+        @Override
+        public boolean ready() {
+            return MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getTemplate());
+        }
+
+        @Override
+        public void parse() {
+            builderFormDatas(ConstructionSchedule.class);
+
+            List<ChapterSchedule> chapterSchedules=chapterScheduleFc.apply(tec.getContractId().toString());
+            /*支付信息根据章节、月份分组*/
+            List<InventoryForm> inventoryForms = tec.meterInfo.getInventoryForms();
+            List<InventoryForm> chapters = tec.meterInfo.getChapter();
+            /*合同金额*/
+            Map<String, BigDecimal[]> contractMoney = contractMoneySum.apply(inventoryForms);
+            LinkedHashMap<String, InventoryForm> dictMap = chapters.stream().collect(Collectors.toMap(e->chapterPreFixFc.apply(e),e -> e, (v1, v2) -> v1,LinkedHashMap::new));
+            LinkedHashMap<Integer,List<Payment>>paymentListMap = tec.meterInfo.getPaymentListMap();
+            /*之前的计量期数据*/
+            previous = paymentListMap.get(MeterInfo.PRE);
+            /*当前计量期数据*/
+            current =paymentListMap.get(MeterInfo.CUR);
+            /*累计到本期末*/
+            paymentsPeriodEnd=paymentListMap.get(MeterInfo.END);
+            /*往期每章节的实际花费*/
+            Map<String,BigDecimal> previousMoney= moneySum.apply(previous);
+            /*当前计量期每章节的实际花费*/
+            Map<String,BigDecimal> currentMoney= moneySum.apply(current);
+            /*本期末每章节的实际花费*/
+            Map<String,BigDecimal> endMoney= moneySum.apply(paymentsPeriodEnd);
+
+          /*按计量期的年月的时间戳分组*/
+            LinkedHashMap<Integer,BigDecimal> monthMoney = paymentsPeriodEnd.stream().sorted(Comparator.comparingInt(Payment::dateInt)).collect(Collectors.groupingBy(
+                    Payment::dateInt,
+                    LinkedHashMap::new,
+                    Collectors.reducing(BigDecimal.ZERO, Payment::getMoneyAsBigDecimal, BigDecimal::add)
+            ));
+
+            BaseInfo baseInfo = tec.meterInfo.getBaseInfo();
+            dictMap.forEach((k,v)-> {
+                ConstructionSchedule cs = new ConstructionSchedule(v.getFormName());
+                BigDecimal[] sum = contractMoney.get(k);
+                cs.setChapterNumber(k);
+                cs.setContractMoney(sum[0].toPlainString());
+                cs.setChangeMoney(sum[1].toPlainString());
+                cs.setCurrentPeriodPay(StringUtils.handleNull(currentMoney.get(k)));
+                cs.setCurrentPeriodEndPay(StringUtils.handleNull(endMoney.get(k)));
+                cs.setItemPercent(ratioFc.apply(cs.getChangeMoney(), baseInfo.getContractAmount().toString()));
+                cs.setItemProgress(ratioFc.apply(cs.getCurrentPeriodEndPay(), cs.getChangeMoney()));
+                cs.setCurrentPayPercent(ratioFc.apply(cs.getCurrentPeriodPay(),cs.getChangeMoney()));
+                /* 本期末累计支付金额占合同比*/
+                cs.setPayPercent(ratioFc.apply(cs.getCurrentPeriodEndPay(),cs.getChangeMoney()));
+                /*本期末占合合同金额 */
+                cs.setPrePayPercent(ratioFc.apply(cs.getCurrentPeriodEndPay(),cs.getContractMoney()));
+                /*变更金额*/
+                cs.setChangeMoneyAll(subtractFc.apply(cs.getChangeMoney(),cs.getContractMoney()));
+                dataList.add(cs);
+            });
+            /*每月合计进度*/
+            try {
+                String totalAmount=dataList.stream().map(ConstructionSchedule::getContractMoney).map(BaseUtils::str2BigDecimal).reduce(BigDecimal.ZERO,BigDecimal::add).toPlainString();
+                /*合同计划结束日期年末*/
+                LocalDate planEndDate=LocalDate.parse(baseInfo.getEndDatePlan(),BaseUtils.chineseDateFm);
+                LocalDate planStartDate=LocalDate.parse(baseInfo.getEndDatePlan(),BaseUtils.chineseDateFm);
+                int max = monthMoney.keySet().stream().max(Comparator.comparingInt(i->i)).orElse(BaseUtils.dateInt(planEndDate.getYear(),12));
+                int min= monthMoney.keySet().stream().min(Comparator.comparingInt(i->i)).orElse(BaseUtils.dateInt(planStartDate.getYear(),1));
+                List<Integer> tickUnit =BaseUtils.getTickUnit(min,max);
+                /*没月累计*/
+              /*  LocalDateTime head=BaseUtils.toLdt(min);
+                LocalDateTime tail=BaseUtils.toLdt(max);*/
+               /* List<String> monthlySum= IntStream.rangeClosed(1,max).boxed().map(month->{
+                    BigDecimal tmp=  monthMoney.entrySet().stream().filter(e->e.getKey()<=month).map(Map.Entry::getValue).reduce(BigDecimal.ZERO,BigDecimal::add);
+                    return  ratioFc.apply(tmp.toPlainString(),totalAmount);
+                }).collect(Collectors.toList());*/
+                List<String> monthlySum=  tickUnit.stream().map(month->{
+                    BigDecimal tmp=  monthMoney.entrySet().stream().filter(e->e.getKey()<=month).map(Map.Entry::getValue).reduce(BigDecimal.ZERO,BigDecimal::add);
+                    return  ratioFc.apply(tmp.toPlainString(),totalAmount);
+                }).collect(Collectors.toList());
+
+                FormulaUtils.elementFindByCode(fdm,ConstructionSchedule.TBN+":key_22").ifPresent(t->{
+                    elementWriter.write(t,monthlySum);
+                });
+                /*本月*/
+              /*List<String> monthlyCount= IntStream.rangeClosed(1,max).boxed().map(month->{
+                    BigDecimal tmp=  monthMoney.entrySet().stream().filter(e-> e.getKey().equals(month)).map(Map.Entry::getValue).reduce(BigDecimal.ZERO,BigDecimal::add);
+                    return  ratioFc.apply(tmp.toPlainString(),totalAmount);
+                }).collect(Collectors.toList());*/
+                List<String> monthlyCount= tickUnit.stream().map(month->{
+                    BigDecimal tmp=  monthMoney.entrySet().stream().filter(e-> e.getKey().equals(month)).map(Map.Entry::getValue).reduce(BigDecimal.ZERO,BigDecimal::add);
+                    return  ratioFc.apply(tmp.toPlainString(),totalAmount);
+                }).collect(Collectors.toList());
+
+                FormulaUtils.elementFindByCode(fdm,ConstructionSchedule.TBN+":key_23").ifPresent(t->{
+                    elementWriter.write(t,monthlyCount);
+                });
+
+                List<String> planMonthSum=new ArrayList<>();
+                LinkedHashMap<Integer,BigDecimal> planMonthMap=new LinkedHashMap<>();
+                if(chapterSchedules!=null&&chapterSchedules.size()>0) {
+                    /*月份装入数组*/
+                    chapterSchedules.forEach(ChapterSchedule::updateArray);
+                    LinkedHashMap<Integer,List<ChapterSchedule>> chapterScheduleGroup= chapterSchedules.stream().sorted(Comparator.comparingInt(ChapterSchedule::getYear)).collect(Collectors.groupingBy(ChapterSchedule::getYear,LinkedHashMap::new,Collectors.toList()));
+                    chapterScheduleGroup.forEach((year,v)->{
+                       for(int i=1;i<=12;i++){
+                           int month = i;
+                           planMonthMap.put(BaseUtils.dateInt(year,month),v.stream().map(e->e.getArr()[month-1]).reduce(BigDecimal.ZERO,BigDecimal::add));
+                       }
+                    });
+                   /* List<BigDecimal> planMonth = IntStream.range(0,12).boxed().map(i->chapterSchedules.stream().map(e->e.getArr()[i]).reduce(BigDecimal.ZERO,BigDecimal::add)).collect(Collectors.toList());*/
+                    /*计划本月*/
+                    FormulaUtils.elementFindByCode(fdm, ConstructionSchedule.TBN + ":key_28").ifPresent(t -> {
+                        List<String> value=planMonthMap.values().stream().map(BigDecimal::toPlainString).map(s-> ratioFc.apply(s, totalAmount)).collect(Collectors.toList());
+                        elementWriter.write(t, value);
+                    });
+                    /*计划累计*/
+
+                    planMonthSum = planMonthMap.keySet().stream().map(yearMonth->{
+                        String tmp=  planMonthMap.entrySet().stream().filter(kv ->kv.getKey()<=yearMonth).map(Map.Entry::getValue).reduce(BigDecimal.ZERO, BigDecimal::add).toPlainString();
+                        return ratioFc.apply(tmp, totalAmount);
+                    }).collect(Collectors.toList());
+
+                     /*       planMonthSum = IntStream.range(0,12).boxed().map(i-> {
+                                String tmp=  planMonth.stream().filter(e -> planMonth.indexOf(e) <= i).reduce(BigDecimal.ZERO, BigDecimal::add).toPlainString();
+                                return ratioFc.apply(tmp, totalAmount);
+                            }      */
+                    List<String> finalPlanMonthSum = planMonthSum;
+                    FormulaUtils.elementFindByCode(fdm, ConstructionSchedule.TBN + ":key_27").ifPresent(t -> {
+                        elementWriter.write(t, finalPlanMonthSum);
+                    });
+
+                }
+                /*上传图标*/
+                if(planMonthSum.size()>0&&monthlySum.size()>0){
+                    try {
+                        LinkedHashMap<Long,Double> actualMap  = new LinkedHashMap<>();
+                        monthMoney.forEach((yearMonth,sum)->{
+                            actualMap.put(BaseUtils.getTimeMs(yearMonth/100,yearMonth%100),sum.doubleValue());
+                        });
+
+                        LinkedHashMap<Long,Double> plannedMap =new LinkedHashMap<>();
+                        planMonthMap.entrySet().stream().filter(kv->kv.getKey()<=max).forEach(kv->{
+                            plannedMap.put(BaseUtils.getTimeMs(kv.getKey()/100,kv.getKey()%100),kv.getValue().doubleValue());
+                        });
+                        String path=FormulaUtils.chapterScheduleChartUrl(actualMap,plannedMap,planStartDate.getYear(),planEndDate.getYear());
                         BladeFile chartFile= tec.getNewIOSSClient().uploadFile( ConstructionSchedule.TBN+ SnowFlakeUtil.getId() + ".png",path);
                         /*施工进度图*/
                         FormulaUtils.elementFindByCode(fdm, ConstructionSchedule.TBN + ":key_29").ifPresent(t -> {

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IFormulaDao.java

@@ -46,5 +46,5 @@ public interface IFormulaDao {
     /**获取中期支付证书项目详情*/
     Function<String, List<InterimPayCertificateItem>> getInterimPayCertificateItemFc();
     /**获取资金计划*/
-    BiFunction<String,String, List<ChapterSchedule>> getChapterScheduleFc();
+    Function<String, List<ChapterSchedule>> getChapterScheduleFc();
 }

+ 4 - 4
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaDaoImpl.java

@@ -158,7 +158,7 @@ public class FormulaDaoImpl implements IFormulaDao {
     @Override
     public Function<Long, List<Payment>> getPaymentListFc() {
         return contractId->{
-            String paySql="select  a.id,a.form_number number,a.form_name name ,a.middle_meter_id,a.current_meter_total completed ,a.current_price price,current_meter_money money,meter_number meterNumber,a.business_date ,contract_meter_id meterId,b.id formId,b.chapter_number chapter, b.contract_money contractMoney,b.change_money,b.unit,contract_total ,change_total,c.sort,c.id periodId from s_inventory_form_apply a join s_contract_inventory_form b on a.contract_form_id=b.id join s_contract_meter_period c on a.contract_period_id=c.id where a.is_deleted=0  and a.contract_id="+contractId;
+            String paySql="select  a.id,a.form_number number,a.form_name name ,a.middle_meter_id,a.current_meter_total completed ,a.current_price price,current_meter_money money,meter_number meterNumber,a.business_date ,contract_meter_id meterId,b.id formId,b.chapter_number chapter, b.contract_money contractMoney,b.change_money,b.unit,contract_total ,change_total,c.sort,c.id periodId ,c.period_year,c.period_month from s_inventory_form_apply a join s_contract_inventory_form b on a.contract_form_id=b.id join s_contract_meter_period c on a.contract_period_id=c.id where a.is_deleted=0  and a.contract_id="+contractId;
             return this.jdbcTemplate.query(paySql,new BeanPropertyRowMapper<>(Payment.class));
         };
     }
@@ -239,9 +239,9 @@ public class FormulaDaoImpl implements IFormulaDao {
     }
 
     @Override
-    public BiFunction<String,String, List<ChapterSchedule>> getChapterScheduleFc() {
-        return  (year,contractId)->{
-            String sql="select b.one,b.two,b.three,b.four,b.five,b.six,b.seven,b.eight,b.nine,b.ten,b.eleven,b.twelve,c.form_name,c.form_number from  s_form_period  a join s_form_period_detail b on a.id=b.form_period_id join s_contract_inventory_form c on b.contract_form_id=c.id where period_year="+year+" and a.contract_id="+contractId+" and a.is_deleted=0 and b.is_deleted=0";
+    public Function<String, List<ChapterSchedule>> getChapterScheduleFc() {
+        return  (contractId)->{
+            String sql="select b.one,b.two,b.three,b.four,b.five,b.six,b.seven,b.eight,b.nine,b.ten,b.eleven,b.twelve,c.form_name,c.form_number,period_year year from  s_form_period  a join s_form_period_detail b on a.id=b.form_period_id join s_contract_inventory_form c on b.contract_form_id=c.id where  a.contract_id="+contractId+" and a.is_deleted=0 and b.is_deleted=0";
             return getEntityList(sql,ChapterSchedule.class);
         };
     }