yangyj 1 ano atrás
pai
commit
b59b7c6842

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

@@ -0,0 +1,45 @@
+package org.springblade.manager.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author yangyj
+ * @Date 2024/6/25 15:15
+ * @description 资金计划
+ */
+@Data
+public class ChapterSchedule {
+     private String formNumber;
+     private String formName;
+    private BigDecimal one=BigDecimal.ZERO;
+    private BigDecimal two=BigDecimal.ZERO;
+    private BigDecimal three=BigDecimal.ZERO;
+    private BigDecimal four=BigDecimal.ZERO;
+    private BigDecimal five=BigDecimal.ZERO;
+    private BigDecimal six=BigDecimal.ZERO;
+    private BigDecimal seven=BigDecimal.ZERO;
+    private BigDecimal eight=BigDecimal.ZERO;
+    private BigDecimal nine=BigDecimal.ZERO;
+    private BigDecimal ten=BigDecimal.ZERO;
+    private BigDecimal eleven=BigDecimal.ZERO;
+    private BigDecimal twelve=BigDecimal.ZERO;
+    private BigDecimal[] arr = new BigDecimal[12];
+    public void updateArray() {
+        arr[0] = one;
+        arr[1] = two;
+        arr[2] = three;
+        arr[3] = four;
+        arr[4] = five;
+        arr[5] = six;
+        arr[6] = seven;
+        arr[7] = eight;
+        arr[8] = nine;
+        arr[9] = ten;
+        arr[10] = eleven;
+        arr[11] = twelve;
+    }
+
+}

+ 26 - 16
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ConstructionSchedule.java

@@ -17,29 +17,31 @@ public class ConstructionSchedule implements  DataModel{
     public static final String TBN="ConSch";
     public static final String TBN_CH="施工进度表";
     /**支付编号*/
-    @JSONField(name = "key_0",label="支付编号")
-    private String formNumber;
+  /*  @JSONField(name = "key_0",label="支付编号")
+    private String formNumber;*/
+    @JSONField(name = "key_0",label="章编号")
+    private String chapterNumber;
     /**项目名称*/
-    @JSONField(name = "key_1",label="项目名称",ordinal = 1)
-    private String itemName;
-    /**计量单位*/
+    @JSONField(name = "key_1",label="名称",ordinal = 1)
+    private String chapterName;
+  /*  *//**计量单位*//*
     @JSONField(name = "key_2",label="计量单位",ordinal = 2)
     private String unit;
-    /**合同数量*/
+    *//**合同数量*//*
     @JSONField(name = "key_3",label="合同数量",ordinal = 3)
     private String contractTotal;
-    /**变更数量*/
+    *//**变更数量*//*
     @JSONField(name = "key_4",label="变更数量",ordinal = 4)
     private String changeTotal;
-    /**本次完成数量*/
+    *//**本次完成数量*//*
     @JSONField(name = "key_5",label="本次完成数量",ordinal = 5)
     private String currentPeriodCompleted;
-    /**至上期完成数量*/
+    *//**至上期完成数量*//*
     @JSONField(name = "key_15",label="至上期完成数量",ordinal = 5)
     private String previousPeriodCompleted;
-    /**累计完成数量*/
+    *//**累计完成数量*//*
     @JSONField(name = "key_6",label="累计完成数量",ordinal = 6)
-    private String completed;
+    private String completed;*/
     /**合同金额*/
     @JSONField(name = "key_7",label="合同金额",ordinal = 7)
     private String contractMoney;
@@ -88,8 +90,15 @@ public class ConstructionSchedule implements  DataModel{
     @JSONField(name = "key_22",label="累计实际完成-ZJ",ordinal = 102)
     private String actualCompletion;
     /**本次实际完成*/
-    @JSONField(name = "key_23",label="本实际完成-ZJ",ordinal = 102)
+    @JSONField(name = "key_23",label="本实际完成-ZJ",ordinal = 102)
     private String currentCompletion;
+    @JSONField(name = "key_27",label="计划累计实际完成-ZJ",ordinal = 102)
+    private String planCompletion;
+    /**本次实际完成*/
+    @JSONField(name = "key_28",label="计划本月实际完成-ZJ",ordinal = 102)
+    private String planMonthCompletion;
+    @JSONField(name = "key_29",label="施工进度图",ordinal = 102)
+    private String chartUrl;
     /**合同概要*/
     @JSONField(name = "key_24",label="合同概要-ZJ",ordinal = 106)
     private String contractSummary;
@@ -99,14 +108,14 @@ public class ConstructionSchedule implements  DataModel{
     private String pageIndex;
 
 
-    public ConstructionSchedule(String itemName) {
-        this.itemName = itemName;
+    public ConstructionSchedule(String chapterName) {
+        this.chapterName = chapterName;
         this.currentPeriodPay = "0.0";
         this.currentPeriodEndPay = "0.0";
     }
 
-    public ConstructionSchedule(String itemName, String currentPeriodPay, String currentPeriodEndPay) {
-        this.itemName = itemName;
+    public ConstructionSchedule(String chapterName, String currentPeriodPay, String currentPeriodEndPay) {
+        this.chapterName = chapterName;
         this.currentPeriodPay = currentPeriodPay;
         this.currentPeriodEndPay = currentPeriodEndPay;
     }
@@ -114,4 +123,5 @@ public class ConstructionSchedule implements  DataModel{
     public ConstructionSchedule() {
     }
 
+
 }

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

@@ -33,7 +33,7 @@ public class MeterInfo {
     /**计量单元树列表*/
     List<MeterTree> meterTreeList;
     /**模版*/
-    private Integer config=MB_GX;
+    private Integer template =MB_GX;
     /**合同信息*/
     BaseInfo baseInfo;
     /**本合同段所有中期计量期信息(如果需要也可以是材料预、开工的计量期)*/

+ 3 - 2
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/Payment.java

@@ -3,6 +3,7 @@ package org.springblade.manager.vo;
 import lombok.Data;
 
 import java.math.BigDecimal;
+import java.time.LocalDate;
 
 /**
  * @author yangyj
@@ -46,8 +47,8 @@ public class Payment {
     private Integer sort;
     /**中间计量期*/
     private Long periodId;
-
-
+    /**业务日期*/
+    private LocalDate businessDate;
     public BigDecimal getMoneyAsBigDecimal() {
         try {
             return new BigDecimal(getMoney());

+ 149 - 2
blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java

@@ -30,21 +30,30 @@ import org.jfree.chart.ChartFactory;
 import org.jfree.chart.ChartPanel;
 import org.jfree.chart.ChartUtils;
 import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.CategoryAxis;
 import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.axis.NumberTickUnit;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.CategoryPlot;
 import org.jfree.chart.plot.PlotOrientation;
 import org.jfree.chart.plot.ValueMarker;
 import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.category.BarRenderer;
+import org.jfree.chart.renderer.category.LineAndShapeRenderer;
 import org.jfree.chart.renderer.xy.XYSplineRenderer;
 import org.jfree.chart.title.TextTitle;
+import org.jfree.data.category.CategoryDataset;
+import org.jfree.data.category.DefaultCategoryDataset;
 import org.jfree.data.xy.XYSeries;
 import org.jfree.data.xy.XYSeriesCollection;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
+import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.BaseUtils;
 import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.common.utils.SystemUtils;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.bean.TableInfo;
 import org.springblade.manager.dto.*;
@@ -55,14 +64,17 @@ import org.springblade.manager.formula.impl.CompositeDataAccess;
 import org.springblade.manager.formula.impl.TableElementConverter;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.vo.*;
+import org.springblade.system.cache.ParamCache;
 import org.springframework.core.annotation.AnnotationUtils;
 import reactor.core.publisher.Mono;
 
+import javax.imageio.ImageIO;
 import java.awt.*;
 import java.awt.Font;
 import java.awt.Shape;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
 import java.io.*;
 
 import java.lang.annotation.Annotation;
@@ -1091,8 +1103,9 @@ public class FormulaUtils {
         return null;
     }
 
+
     public static void mainT(String[] args) throws IOException {
-        XYSeries series = new XYSeries("Data Series");
+        XYSeries series = new XYSeries("每月实际完成");
         series.add(10.2, 1.82);
         series.add(11.9, 1.86);
         series.add(15.9, 1.87);
@@ -1103,7 +1116,7 @@ public class FormulaUtils {
         dataset.addSeries(series);
 
         JFreeChart chart = ChartFactory.createXYLineChart(
-                "测试散点图", // 标题
+                "按月进度", // 标题
                 "X", // 横轴标题
                 "Y", // 纵轴标题
                 dataset, // 数据集
@@ -1151,6 +1164,140 @@ public class FormulaUtils {
 
     }
 
+    private static CategoryDataset createDataset( double[] actualProgress, double[] plannedProgress) {
+        String[] months = {"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};
+  /*      int[] actualProgress = {10, 15, 18, 27, 35, 48};
+        int[] plannedProgress = {10, 15, 20, 25, 30, 35};*/
+        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
+
+        for (int i = 0; i < actualProgress.length; i++) {
+            dataset.addValue(actualProgress[i], "实际进度", months[i]);
+        }
+
+        for (int i = 0; i < plannedProgress.length; i++) {
+            dataset.addValue(plannedProgress[i], "计划进度", months[i]);
+        }
+
+        return dataset;
+    }
+
+    private static JFreeChart createChart(CategoryDataset dataset) {
+        JFreeChart chart = ChartFactory.createBarChart(
+                "施工进度对比图",
+                "月份",
+                "进度 (%)",
+                dataset,
+                PlotOrientation.VERTICAL,
+                true,
+                true,
+                false
+        );
+
+        CategoryPlot plot = (CategoryPlot) chart.getPlot();
+        // 设置中文字体以避免乱码
+        Font font = new Font("宋体", Font.PLAIN, 12);
+        chart.getTitle().setFont(font);
+        plot.getDomainAxis().setTickLabelFont(font);
+        plot.getDomainAxis().setLabelFont(font);
+        plot.getRangeAxis().setTickLabelFont(font);
+        plot.getRangeAxis().setLabelFont(font);
+        chart.getLegend().setItemFont(font);
+        plot.setDomainAxis(new CategoryAxis("月份"));
+        plot.setRangeAxis(new NumberAxis("进度 (%)"));
+
+        BarRenderer barRenderer = new BarRenderer();
+        barRenderer.setSeriesPaint(0, new Color(0, 0, 255));
+        barRenderer.setSeriesPaint(1, new Color(0, 255, 0));
+        plot.setRenderer(barRenderer);
+
+        // 添加第二个数据集,绘制为曲线
+        DefaultCategoryDataset lineDataset = new DefaultCategoryDataset();
+        String[] months = {"一月", "二月", "三月", "四月", "五月", "六月"};
+        int[] actualProgress = {10, 15, 18, 27, 35, 48};
+        int[] plannedProgress = {10, 15, 20, 25, 30, 35};
+
+        for (int i = 0; i < actualProgress.length; i++) {
+            lineDataset.addValue(actualProgress[i], "实际进度", months[i]);
+        }
+
+        for (int i = 0; i < plannedProgress.length; i++) {
+            lineDataset.addValue(plannedProgress[i], "计划进度", months[i]);
+        }
+
+        plot.setDataset(1, lineDataset);
+        plot.mapDatasetToRangeAxis(1, 0);
+
+        LineAndShapeRenderer lineRenderer = new LineAndShapeRenderer();
+        lineRenderer.setSeriesPaint(0, new Color(255, 0, 0));
+        lineRenderer.setSeriesPaint(1, new Color(255, 165, 0));
+        plot.setRenderer(1, lineRenderer);
+
+        // 设置 X 轴标签
+        CategoryAxis domainAxis = plot.getDomainAxis();
+        domainAxis.setCategoryLabelPositions(
+                org.jfree.chart.axis.CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 4.0)
+        );
+        // 设置 Y 轴范围
+        ValueAxis rangeAxis = plot.getRangeAxis();
+        rangeAxis.setRange(0, 100);
+
+        return chart;
+    }
+
+    public static void mainT2(String[] args) {
+        double[] actualProgress = {10, 15, 18, 27, 35, 48};
+        double[] plannedProgress = {10, 15, 20, 25, 30, 35};
+        CategoryDataset dataset = createDataset(actualProgress,plannedProgress);
+        JFreeChart chart = createChart(dataset);
+
+        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            BufferedImage bufferedImage = chart.createBufferedImage(800, 600);
+            ImageIO.write(bufferedImage, "png", out);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+/*        try {
+            ChartUtils.saveChartAsPNG(new File("C:/Users/yangyj/Desktop/Swap_space/poi_statistics.png"), chart, 800, 600);
+            // 保存图表到内存
+        } catch (Exception e) {
+            e.printStackTrace();
+        }*/
+    }
+
+    public static String getSysLocalFileUrl() {
+        String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        if (org.springblade.common.utils.SystemUtils.isMacOs()) {
+            file_path = "/Users/hongchuangyanfa/Desktop/";
+        } else if (SystemUtils.isWindows()) {
+            file_path = "C://upload//";
+        }
+        return file_path;
+    }
+    public static byte[]  chapterScheduleChart( double[] actualProgress ,double[] plannedProgress){
+        CategoryDataset dataset = createDataset(actualProgress,plannedProgress);
+        JFreeChart chart = createChart(dataset);
+        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            BufferedImage bufferedImage = chart.createBufferedImage(800, 600);
+            ImageIO.write(bufferedImage, "png", out);
+            return out.toByteArray();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static String  chapterScheduleChartUrl( double[] actualProgress ,double[] plannedProgress){
+        CategoryDataset dataset = createDataset(actualProgress,plannedProgress);
+        JFreeChart chart = createChart(dataset);
+          try {
+              String path= getSysLocalFileUrl() + "/pdf//"+SnowFlakeUtil.getId()+".png";
+            ChartUtils.saveChartAsPNG(new File(path), chart, 800, 600);
+            return path;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
 
 
     /**字符串sha256映射*/

+ 187 - 28
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/ExecutorMeter.java

@@ -8,6 +8,8 @@ import com.mixsmart.utils.StringUtils;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import org.springblade.common.utils.BaseUtils;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.StringPool;
 import org.springblade.manager.dto.ElementData;
@@ -19,6 +21,7 @@ import org.springblade.meter.entity.InterimPayCertificateItem;
 import org.springframework.beans.BeanUtils;
 
 
+import java.io.ByteArrayOutputStream;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDate;
@@ -39,6 +42,8 @@ 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 ElementWriter elementWriter;
     /**执行链*/
     private List<Special> specialList = new ArrayList<>();
@@ -82,12 +87,10 @@ public class ExecutorMeter extends FormulaExecutor {
     /*按照二级清单编号,合计合同清单{合同金额,变更金额}*/
     private Function<List<InventoryForm>, Map<String, BigDecimal[]>> contractMoneySum = data -> data.stream()
             .collect(Collectors.groupingBy(
-                    form -> getPrefix(form.getFormNumber()),
+                    this::getPrefix,
                     Collectors.reducing(
                             new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO},
                             form -> new BigDecimal[]{
-                                    /*form.getContractMoney() != null ? new BigDecimal(form.getContractMoney()) : BigDecimal.ZERO,
-                                    form.getChangeMoney() != null ? new BigDecimal(form.getChangeMoney()) : BigDecimal.ZERO*/
                                     BaseUtils.str2BigDecimal(form.getContractMoney()),
                                     BaseUtils.str2BigDecimal(form.getChangeMoney())
                             },
@@ -102,6 +105,8 @@ public class ExecutorMeter extends FormulaExecutor {
                     Collectors.reducing(BigDecimal.ZERO, Payment::getMoneyAsBigDecimal, BigDecimal::add)
             ));
 
+
+
     Function<InventoryForm,String> level2Fn=inventoryForm -> {
         String prefix = inventoryForm.getFormNumber();
         if(inventoryForm.getFormName().contains(BTDL)){
@@ -132,12 +137,27 @@ public class ExecutorMeter extends FormulaExecutor {
         return fn;
     }
 
-
+    public String getPrefix(InventoryForm inventoryForm){
+        String prefix=inventoryForm.getFormNumber();
+        if(prefix!=null) {
+            boolean hasWord = inventoryForm.getFormName().contains(BTDL)||inventoryForm.getFormNumber().contains(BTDL);
+            String  fn= prefix.split("-")[0];
+            /*204-1-11(保通道路)*/
+            if (BaseUtils.isNumber(fn)) {
+                fn = String.valueOf(100 * (Integer.parseInt(fn) / 100));
+            }
+            if(hasWord){
+                fn=fn+":"+BTDL;
+            }
+            return fn;
+        }
+        return "NULL";
+    }
 
 
     Function<InventoryForm,String> chapterPreFixFc=inventoryForm->{
         if(inventoryForm.getFormName().contains(BTDL)){
-            return inventoryForm.getFormNumber()+BTDL;
+            return inventoryForm.getFormNumber()+":"+BTDL;
         }
         return inventoryForm.getFormNumber();
     } ;
@@ -174,7 +194,7 @@ public class ExecutorMeter extends FormulaExecutor {
             /*分项工程中期支付汇总*/
             this.specialList.add(new SubIPaySum());
             /*施工进度表*/
-            this.specialList.add(new ConSch());
+            this.specialList.add(new ConSchChapter());
             /*分项工程中期计量支付表*/
             this.specialList.add(new SubIMeterPay());
             this.specialList.add(new IMeterPaySummary());
@@ -292,7 +312,7 @@ public class ExecutorMeter extends FormulaExecutor {
 
         @Override
         public boolean ready() {
-            return fds.size()==14&&!MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getConfig());
+            return fds.size()==14&&!MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getTemplate());
         }
 
         public void parse(){
@@ -367,7 +387,7 @@ public class ExecutorMeter extends FormulaExecutor {
      /*永久性工程材料差价金额一览表*/
         @Override
         public boolean ready() {
-            return MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getConfig());
+            return MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getTemplate());
         }
 
         @Override
@@ -541,7 +561,7 @@ public class ExecutorMeter extends FormulaExecutor {
 
         @Override
         public boolean ready() {
-            return MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getConfig());
+            return MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getTemplate());
         }
 
         @Override
@@ -652,19 +672,6 @@ public class ExecutorMeter extends FormulaExecutor {
             /*数据获取start*/
              /*合同计量清单*/
              List<InventoryForm> inventoryForms = tec.meterInfo.getInventoryForms();
-          /*   InventoryForm root = null;
-             for(InventoryForm itf:inventoryForms){
-                 if(itf.getParentId()==0){
-                     root = itf;
-                     break;
-                 }
-             }
-            for(InventoryForm itf:inventoryForms){
-                assert root != null;
-                if(itf.getParentId().equals(root.getId())){
-                    chapters.add(itf);
-                }
-            }*/
             List<InventoryForm> chapters = tec.meterInfo.getChapter();
             LinkedHashMap<Integer,List<ChangeToken>> changeTokenListMap= tec.meterInfo.getChangeTokenListMap();
             /* 本期变更 */
@@ -735,7 +742,7 @@ public class ExecutorMeter extends FormulaExecutor {
                  /*合计后回显*/
                  Map<InterimPaymentCertificate,InterimPayCertificateItem> peerMap = new HashMap<>();
                  List<InterimPaymentCertificate> payItemZj=new ArrayList<>();
-                 if(MeterInfo.MB_ZJ.equals(tec.meterInfo.getConfig())){
+                 if(MeterInfo.MB_ZJ.equals(tec.meterInfo.getTemplate())){
                      InterimPaymentCertificate xj=new InterimPaymentCertificate("小计",true);
                      addGetSetConfig(xj,summaryConfigMap,InterimPaymentCertificate::getContractAmount,xj::setContractAmount);
                      addGetSetConfig(xj,summaryConfigMap,InterimPaymentCertificate::getRevisedTotal,xj::setRevisedTotal);
@@ -800,7 +807,7 @@ public class ExecutorMeter extends FormulaExecutor {
                      InterimPaymentCertificate ipc = paymentCertificateMap.get(e.getPayNumber());
                      if(ipc==null){
                          /*浙江的按照实际的计量单元去显示*/
-                         if(!MeterInfo.MB_ZJ.equals(tec.meterInfo.getConfig())) {
+                         if(!MeterInfo.MB_ZJ.equals(tec.meterInfo.getTemplate())) {
                              ipc = new InterimPaymentCertificate(e.getPayName());
                          }
                      }
@@ -948,7 +955,7 @@ public class ExecutorMeter extends FormulaExecutor {
                 summary.setPayRatioB(ratioFc.apply(summary.getCurrentPeriodEndPay(),summary.getRevisedAmount()));
                 dataList.add(summary);
 
-                if(MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getConfig())){
+                if(MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getTemplate())){
                     /*浙江*/
                     Function<Function<InterimPaymentSummary,String>,Function<List<InterimPaymentSummary>,List<Object>>> fc=(f)-> dl->dl.stream().map(f).flatMap(e->{
                         List<Object> l=IntStream.range(0,5).boxed().map(i->"").collect(Collectors.toList());
@@ -1175,13 +1182,165 @@ public class ExecutorMeter extends FormulaExecutor {
 
     }
 
+    @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.periodInfo.getYear(),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.comparing(Payment::getBusinessDate)).collect(Collectors.groupingBy(
+                    payment -> payment.getBusinessDate().getMonthValue(),
+                    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(subtractFc.apply(cs.getCurrentPeriodEndPay(),cs.getCurrentPeriodPay()),cs.getContractMoney()));
+                /*变更金额*/
+                cs.setChangeMoneyAll(subtractFc.apply(cs.getChangeMoney(),cs.getContractMoney()));
+                dataList.add(cs);
+            });
+            /*每月合计进度*/
+            try {
+                int max = monthMoney.keySet().stream().max(Comparator.comparingInt(i->i)).orElse(12);
+                /*没月累计*/
+                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  multiFc.apply(ratioFc.apply(tmp.toPlainString(),baseInfo.getTotalAmount().toString()),"100");
+                }).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(),baseInfo.getTotalAmount().toString());
+                }).collect(Collectors.toList());
+                FormulaUtils.elementFindByCode(fdm,ConstructionSchedule.TBN+":key_23").ifPresent(t->{
+                    elementWriter.write(t,monthlyCount);
+                });
+                List<String> planMonthSum=new ArrayList<>();
+                if(chapterSchedules!=null&&chapterSchedules.size()>0) {
+                    chapterSchedules.forEach(ChapterSchedule::updateArray);
+                    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=planMonth.stream().map(BigDecimal::toPlainString).map(s-> multiFc.apply(ratioFc.apply(s,baseInfo.getTotalAmount().toString()),"100")).collect(Collectors.toList());
+                        elementWriter.write(t, value);
+                    });
+                    /*计划累计*/
+                    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 multiFc.apply(ratioFc.apply(tmp,baseInfo.getTotalAmount().toString()),"100");
+                            }
+                    ).collect(Collectors.toList());
+                    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 {
+                        double[] actual = monthlySum.stream().mapToDouble(BaseUtils::obj2DoubleZero).toArray();
+                        double[] planned =planMonthSum.stream().limit(monthlySum.size()).mapToDouble(BaseUtils::obj2DoubleZero).toArray();;
+                        /*byte[]  chartBytes = FormulaUtils.chapterScheduleChart(actual,planned);
+                        BladeFile chartFile= tec.getNewIOSSClient().updateFile(chartBytes, "chart"+SnowFlakeUtil.getId()+".png");*/
+                        String path=FormulaUtils.chapterScheduleChartUrl(actual,planned);
+                        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 ConSch extends   BaseSpecial<ConstructionSchedule> implements Special{
 
         @Override
         public boolean ready() {
-            return subprojectInterimPaymentSummary.size()>0&&MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getConfig());
+            return subprojectInterimPaymentSummary.size()>0&&MeterInfo.MB_ZJ.equals(tec.getMeterInfo().getTemplate());
         }
 
         @Override
@@ -1201,7 +1360,7 @@ public class ExecutorMeter extends FormulaExecutor {
             /*获取最大月份,暂时不考虑跨年*/
             int max=monthMeterMap.keySet().stream().max(Comparator.comparingInt(t->t)).orElse(12);
             BaseInfo baseInfo =tec.meterInfo.getBaseInfo();
-            totalList.sort(Comparator.comparing(e -> getPrefix(e.getFormNumber())));
+            totalList.sort(Comparator.comparing(e -> getPrefix(e.getChapterNumber())));
             totalList.forEach(sis->{
                 /*    单项占合同价的比例*/
                 sis.setItemPercent(ratioFc.apply(sis.getChangeMoney(),baseInfo.getTotalAmount().toString()));
@@ -1217,7 +1376,7 @@ public class ExecutorMeter extends FormulaExecutor {
                 sis.setChangeMoneyAll(subtractFc.apply(sis.getChangeMoney(),sis.getContractMoney()));
                 /*变更金额*/
                 /* 根据月份来获取payment*/
-                Map<Long,List<Payment>> meterPaymentGroup = paymentGroup.get(sis.getFormNumber());
+                Map<Long,List<Payment>> meterPaymentGroup = paymentGroup.get(sis.getChapterNumber());
                 /* 当前月已经累计的*/
                 List<Payment> pl =new ArrayList<>();
                 for(int i=1;i<=max;i++){

+ 6 - 4
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/TableElementConverter.java

@@ -22,9 +22,9 @@ import org.springblade.manager.formula.ITableElementConverter;
 import org.springblade.manager.formula.KeyMapper;
 import org.springblade.manager.formula.NodeTable;
 import org.springblade.manager.vo.*;
+import org.springblade.resource.feign.NewIOSSClient;
 
 import java.util.*;
-import java.util.concurrent.CompletableFuture;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -126,6 +126,8 @@ public class TableElementConverter implements ITableElementConverter {
     public BusInfo busInfo=new BusInfo();
     /**用来集中存放计量相关的数据*/
     public MeterInfo meterInfo = new MeterInfo();
+    /**文件上传工具*/
+    private  NewIOSSClient newIOSSClient;
     /**取小数*/
     public Integer scale = 0;
     public Integer payRadicScale = 2;
@@ -375,7 +377,7 @@ public class TableElementConverter implements ITableElementConverter {
               /*模版选择*/
               for(NodeTable nt:tableAll){
                   if("m_20240222111932_1760504568283660288".equals(nt.getInitTableName())||"m_20240222093331_1760477888294944768".equals(nt.getInitTableName())||"m_20240222110914_1760501976056987648".equals(nt.getInitTableName())||"m_20240222101436_1760488226289614848".equals(nt.getInitTableName())){
-                      meterInfo.setConfig(MeterInfo.MB_ZJ);
+                      meterInfo.setTemplate(MeterInfo.MB_ZJ);
                       break;
                   }
               }
@@ -494,9 +496,9 @@ public class TableElementConverter implements ITableElementConverter {
                        rt.getMergeCellsSet().addAll(mergeCellMaps.get(rt.getInitTableName()));
                    }
                    rt.setPkeyId(report.getPKeyId()); //返回表单的主表Id
-                   if(meterInfo.getConfig()!=null){
+                   if(meterInfo.getTemplate()!=null){
                        /*设置模版类型 广西、浙江或者其他*/
-                       rt.setModelType(meterInfo.getConfig());
+                       rt.setModelType(meterInfo.getTemplate());
                    }
                    reportResults.add(rt);
                    List<FormData> fds =group.get(report.getInitTableName());

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

@@ -7,6 +7,7 @@ import org.springblade.meter.entity.InterimPayCertificateItem;
 
 import java.util.List;
 import java.util.Map;
+import java.util.function.BiFunction;
 import java.util.function.Function;
 
 public interface IFormulaDao {
@@ -42,4 +43,6 @@ public interface IFormulaDao {
     Function<Long, List<MaterialAdjust>> getMaterialAdjustFc();
     /**获取中期支付证书项目详情*/
     Function<String, List<InterimPayCertificateItem>> getInterimPayCertificateItemFc();
+    /**获取资金计划*/
+    BiFunction<String,String, List<ChapterSchedule>> getChapterScheduleFc();
 }

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

@@ -23,6 +23,7 @@ import org.springframework.stereotype.Service;
 
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -136,7 +137,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 ,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 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));
         };
     }
@@ -216,6 +217,14 @@ 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";
+            return getEntityList(sql,ChapterSchedule.class);
+        };
+    }
+
     public <T> List<T> getEntityList(String sql, Class<T> entityClass) {
         return  jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(entityClass));
     }

+ 3 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -40,6 +40,7 @@ import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.vo.*;
 import org.springblade.meter.entity.InterimPayCertificateItem;
 import org.springblade.meter.feign.CertificateItemClient;
+import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.cache.ParamCache;
 import org.springframework.beans.BeanUtils;
 import org.springframework.context.annotation.Lazy;
@@ -105,7 +106,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     /**是否使用表单公式*/
     public final static  boolean isForm=true;
 
-
+    private final NewIOSSClient newIOSSClient;
 
     @Override
     public void execute(TableElementConverter tec) {
@@ -2849,6 +2850,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
         /*转换器上下文声明*/
         TableElementConverter tec = new TableElementConverter(processFds,coordinateMap,tableList);
+        tec.setNewIOSSClient(this.newIOSSClient);
         tec.setProjectId(Long.parseLong(contractInfo.getPId()));
         tec.setESignMaps(eSignMaps);
         tec.setContractId(contractInfo.getId());