Explorar o código

新结算书处理方法

chengqiang %!s(int64=5) %!d(string=hai) anos
pai
achega
3fb8893081

+ 17 - 0
src/main/java/com/jeeplus/common/utils/sg/ExcelUtil.java

@@ -110,6 +110,14 @@ public class ExcelUtil {
         return d;
     }
 
+    /**
+     * 遍历excel页签,column1列,查找值包含st的行,返回column2中数字表示多个列的值
+     * @param importExcel
+     * @param st
+     * @param column1
+     * @param column2
+     * @return
+     */
     public static double[] getBashArray(ImportExcel importExcel,String st,int column1,int[] column2){
         int lastRow = importExcel.getLastDataRowNum();
         int len = column2.length;
@@ -184,6 +192,15 @@ public class ExcelUtil {
 //        return d;
 //    }
 
+    /**
+     *在页签importExcel额第column1列,遍历查找该列中的文字,排除掉为空的,以及不包含“ ”的列(这是因为此方法主要用于变电站清单计价表节点
+     * 查找,当中节点都是以角标+“ ”+节点名称,如 ‘1.1 xx’的形式出现)。找到值与sts数组中值一样的,获取该行column2列的值
+     * @param importExcel
+     * @param sts
+     * @param column1
+     * @param column2
+     * @return
+     */
     public static double[][] getBashArray(ImportExcel importExcel,String[] sts,int column1,int[] column2){
         int lastRow = importExcel.getLastDataRowNum();
         int len = sts.length;

+ 62 - 0
src/main/java/com/jeeplus/modules/sg/overheadline/entity/JkxlDetailFee.java

@@ -2,6 +2,8 @@ package com.jeeplus.modules.sg.overheadline.entity;
 
 import com.jeeplus.common.utils.excel.annotation.ExcelField;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -26,6 +28,7 @@ public class JkxlDetailFee {
     private Double otherCost;   //其他费用
     private Double fees;   //规费
     private Double tex;   //税金
+    private Double cbrSb; //承包人采购设备费
     private Double rgFtFee;  //共性人工分摊费用
     private Double totalFee;   //合计金额
 
@@ -45,6 +48,32 @@ public class JkxlDetailFee {
     private Double cFee;      //差额
     private String hierarchy;  //层级
     private Integer index;    //序号
+    private List<JkxlDetailFee> nodes;//子节点
+
+    public Double getCbrSb() {
+        return cbrSb;
+    }
+
+    public void setCbrSb(Double cbrSb) {
+        this.cbrSb = cbrSb;
+    }
+
+    public JkxlDetailFee(){
+
+    }
+
+    public JkxlDetailFee(String wbsCode){
+        this();
+        this.wbsCode = wbsCode;
+    }
+
+    public List<JkxlDetailFee> getNodes() {
+        return nodes;
+    }
+
+    public void setNodes(List<JkxlDetailFee> nodes) {
+        this.nodes = nodes;
+    }
 
     @ExcelField(title="设备费", align=1, sort=6)
     public Double getSbFee() {
@@ -322,4 +351,37 @@ public class JkxlDetailFee {
         JkxlDetailFee that = (JkxlDetailFee) o;
         return wbsCode.equals(that.wbsCode);
     }
+
+    /**
+     * 将fee添加到子节点列表中
+     * @param fee
+     */
+    public JkxlDetailFee addSubNode(JkxlDetailFee fee){
+        if(fee != null){
+            if(nodes==null){
+                nodes = new ArrayList<>();
+            }
+            nodes.add(fee);
+        }
+        return this;
+    }
+
+    /**
+     * 将fees添加到子节点列表中
+     * @param fees
+     */
+    public JkxlDetailFee addSubNodes(List<JkxlDetailFee> fees){
+        if(nodes==null){
+            nodes = new ArrayList<>();
+        }
+        if(fees!=null && fees.size()>0){
+            for(int i=0;i<fees.size();i++){
+                 JkxlDetailFee fee = fees.get(i);
+                 if(fee!=null){
+                     nodes.add(fee);
+                 }
+            }
+        }
+        return this;
+    }
 }

+ 77 - 75
src/main/java/com/jeeplus/modules/sg/overheadline/service/OverheadLineService.java

@@ -502,11 +502,11 @@ public class OverheadLineService {
         List<Settlement> settlements=SettementUtil.getComparison(settlementList,fbfxTotal,divisiontotal,csFees[0]+csFees[1],cs2Total,qtTotal,gfTotal,cbrTotal);
         Boolean f = SettementUtil.getJgjsDeveloper(settlementList);
         settlementService.save(settlements,id);
-        //将本体工程费用明细存入集合
         double csShare = 0.00;
         double gfShare = 0.00;
         double qtShare = 0.00;
         double texShare = 0.00;
+        //将本体工程费用明细存入集合
         List<JkxlDetailFee> list = new ArrayList<>();
         for(int i=0;i<fbfxFees.length;i++){
             JkxlDetailFee jkxlDetailFee = new JkxlDetailFee();
@@ -523,14 +523,20 @@ public class OverheadLineService {
             double measuresFee2 = DoubleUtil.round2(csFees[1] * rgRate);
             double measuresFee3 = DoubleUtil.round2(cs2Total*fbfxRate); //措施费二
             double qtCost = DoubleUtil.round2(qtFees[2]*fbfxRate);  //除场地租用费、招标代理费外费用根据分部分项合计费用所占比例分摊
+            double indepQt = DoubleUtil.round2((qtFees[0]+qtFees[1])*fbfxRate);
             double gfCost = DoubleUtil.round2(gfTotal*rgRate);  //规费
-            double texCost = DoubleUtil.round2((texTotal+btex)*fbfxRate); //税金
+            double cbrSbCost = DoubleUtil.round2(cbrTotal*fbfxRate);//承包人设备采购费根据分部分项进行分摊
             double totalCost = 0.00;  //合计
+            double payable = 0.00;//应纳税金额
             if(f){
-                totalCost = DoubleUtil.sub(DoubleUtil.add(fbfxCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,texCost),originalFbrCost);
+                payable = DoubleUtil.add(fbfxTotal,csFees[0],csFees[1],cs2Total,qtTotal,gfTotal,cbrTotal-fbrTotal);
+                totalCost = DoubleUtil.add(fbfxCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,cbrSbCost,-originalFbrCost);
             } else {
-                totalCost = DoubleUtil.add(fbfxCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,texCost); //合计
+                payable = DoubleUtil.add(fbfxTotal,csFees[0],csFees[1],cs2Total,qtTotal,gfTotal,cbrTotal);
+                totalCost = DoubleUtil.add(fbfxCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,cbrSbCost); //合计
             }
+            double texCost = DoubleUtil.round2((texTotal+btex)*(totalCost+indepQt)/payable); //税金
+            totalCost = DoubleUtil.add(totalCost,texCost);
             csShare = DoubleUtil.add(csShare,measuresFee1,measuresFee2,measuresFee3);
             qtShare = DoubleUtil.add(qtShare,qtCost);
             gfShare = DoubleUtil.add(gfShare,gfCost);
@@ -552,16 +558,15 @@ public class OverheadLineService {
             jkxlDetailFee.setId(id);
             list.add(jkxlDetailFee);
         }
-
         //承包人采购设备费直接放到 “架线工程”分部分项上
-        if(cbrTotal != 0.00){
-            for(JkxlDetailFee jkxlDetailFee : list){
-                if(jkxlDetailFee.getWbsCode().equals("39400000")){
-                    double total1 = jkxlDetailFee.getTotalFee();
-                    jkxlDetailFee.setTotalFee(cbrTotal+total1);
-                }
-            }
-        }
+//        if(cbrTotal != 0.00){
+//            for(JkxlDetailFee jkxlDetailFee : list){
+//                if(jkxlDetailFee.getWbsCode().equals("39400000")){
+//                    double total1 = jkxlDetailFee.getTotalFee();
+//                    jkxlDetailFee.setTotalFee(cbrTotal+total1);
+//                }
+//            }
+//        }
 //        将措施费、规费、其他费用、税金的分摊差额放到一个有值的本体工程上
         double csDiff =  DoubleUtil.sub(DoubleUtil.add(csFees[0],csFees[1],cs2Total),csShare);
         double qtDiff = DoubleUtil.sub(qtFees[2],qtShare);
@@ -588,15 +593,15 @@ public class OverheadLineService {
                 if(jkxlAdjustFee.getType().contains("减") || jkxlAdjustFee.getType().contains("扣") || jkxlAdjustFee.getType().contains("下浮")){
                     fee = fee* -1;
                 }
-                wsbfee += fee;
+                wsbfee = DoubleUtil.add(wsbfee,fee);
             }
         }
         //计算差额
         double tz = 0.00; //总合计金额
         for(JkxlDetailFee jkxlDetailFee : list){
-            tz += jkxlDetailFee.getTotalFee();
+            tz = DoubleUtil.add(tz,jkxlDetailFee.getTotalFee());
         }
-        double gxFee = Math.abs(gcjsFee-tz-qtFees[0]-qtFees[1]-wsbfee);
+        double gxFee = Math.abs(DoubleUtil.add(gcjsFee,-tz,-qtFees[0],-qtFees[1],-wsbfee));
         //将其他费用存入集合
         JkxlDetailFee jkxlDetailFee1 = new JkxlDetailFee();
         JkxlDetailFee jkxlDetailFee2 = new JkxlDetailFee();
@@ -611,11 +616,13 @@ public class OverheadLineService {
         //保存费用明细
         overheadLineMapper.saveList(list);
         //保存未识别费用
-        JkxlAdjustFee jkxlAdjustFee2 = new JkxlAdjustFee();
-        jkxlAdjustFee2.setId(id);
-        jkxlAdjustFee2.setType(BashInfo.CE);
-        jkxlAdjustFee2.setFee(gxFee);
-        feeAdjustService.save(jkxlAdjustFee2);
+        if(gxFee!=0.00){
+            JkxlAdjustFee jkxlAdjustFee2 = new JkxlAdjustFee();
+            jkxlAdjustFee2.setId(id);
+            jkxlAdjustFee2.setType(BashInfo.CE);
+            jkxlAdjustFee2.setFee(gxFee);
+            feeAdjustService.save(jkxlAdjustFee2);
+        }
     }
 
     /**
@@ -647,6 +654,7 @@ public class OverheadLineService {
         double fbfxFee = ExcelUtil.getDouble(total,BashInfo.JS_FBFX,1,2);  //分部分项工程费
         double texTotal = ExcelUtil.getTex(total);   //税金合计
         double btex = BashInfo.getBtex(total); //获取补税额
+        double fbrTotal = ExcelUtil.getFbr(total); //获取发包人采购设备费
         double gcjsFee = BashInfo.getGcjsFee(total);  //获取工程结算价
 //        从《 措施项目清单计价表(一)》《(二)》获取措施费
         double jzcsTotal = BashInfo.getJzCs(csqd); //建筑措施费合计
@@ -654,14 +662,22 @@ public class OverheadLineService {
         double csTotal = jzcsTotal+azcsTotal;//获取措施费清单计价表一
         double[] azcsFees = BashInfo.getAzCsFees(csqd);// 安装措施费 [0]临时设置+安全文明  [1]剩余和
         double[] jzcsFees = BashInfo.getJzCsFees(csqd); //建筑措施费 [0]临时设置+安全文明  [1]剩余和
-        double cs2Total=0.0; //清单表措施费二合计
+        double jzcs2Total = 0.00; //措施二建筑
+        double azcs2Total = 0.00;  //措施二安装
+        double cs2Total=0.00;  //
         if(ImportExcel.getSheet(csqd2) != null){
-            cs2Total = SubstationInfo.getCsJzFee(csqd2);
+            jzcs2Total = SubstationInfo.getCs2JzFee(csqd2);
+            azcs2Total = SubstationInfo.getCs2AzFee(csqd2);
+            cs2Total=jzcs2Total+azcs2Total;
         }
 //        《承包人采购设备计价表》获取数据
-        double cbrTotal = 0.0;  //承包人采购设备费
+        double cbrJzFee = 0.00; //投标人建筑设备费
+        double cbrAzFee = 0.00; //投标人安装设备费
+        double cbrTotal = 0.00; //投标人合计
         if(ImportExcel.getSheet(cbrsb) != null){
-            cbrTotal = ExcelUtil.getDouble(cbrsb,BashInfo.QT_HJ,0,6);
+            cbrJzFee = BashInfo.getFbrJzFee(cbrsb);
+            cbrAzFee = BashInfo.getFbrAzFee(cbrsb);
+            cbrTotal = DoubleUtil.add(cbrJzFee,cbrAzFee);
         }
 //        《其他项目清单计价表》获取数据
         double qtTotal =  ExcelUtil.getDouble(qt,BashInfo.QT_HJ,0,2);//获取其他项目费合计
@@ -682,6 +698,13 @@ public class OverheadLineService {
         double cs2Share = 0.00;
         double qtShare = 0.00;
         double texShare = 0.00;
+        //应纳税金额
+        double payableTotal = 0.00;
+        if(f){
+            payableTotal = DoubleUtil.add(fbfxFee,csTotal,cs2Total,cbrTotal,qtTotal,gfTotal,-fbrTotal);
+        }else{
+            payableTotal = DoubleUtil.add(fbfxFee,csTotal,cs2Total,cbrTotal,qtTotal,gfTotal);
+        }
 
         if(jzgc==0.00 && azgc==0.00){
             throw new RuntimeException(BashInfo.NUMBERERROR);
@@ -729,21 +752,25 @@ public class OverheadLineService {
                 double originalCbrCost = originalJzFees[i][1];  //原承包人采购
                 double originalFbrCost = originalJzFees[i][2];  //原发包人采购
                 double originalJxrCost = originalJzFees[i][3];   //原机械费
-                double fbfxRate = originalTotalCost/fbfxFee;//分部分项费用占(建筑分部分项和+安装分部分项和)比例
+                double fbfxRate = originalTotalCost/fbfxJzTotal; //分部分项占建筑分部分项比例
+                double fbfxTotalRate = originalTotalCost/fbfxFee;//分部分项费用占(建筑分部分项和+安装分部分项和)比例
 //                (分部分项直接工程费-分部分项进项税额)占(建筑直接工程费合计-建筑甲供材合计进项税额)比例
                 double measureRate = (zjgcJzFee-originalFbrCost/(1+jxslJz)*jxslJz)/(zjgcJzTotal-fbrJzTotal/(1+jxslJz)*jxslJz);
                 double measuresFee1 = DoubleUtil.round2(jzcsFees[0]*measureRate); //措施费一(1)
                 double measuresFee2 = DoubleUtil.round2(jzcsFees[1]*measureRate);   //措施费一(2)
-                double measuresFee3 = DoubleUtil.round2(cs2Total*fbfxRate); //措施费二
+                double measuresFee3 = DoubleUtil.round2(jzcs2Total*fbfxRate); //措施费二
                 double gfCost = DoubleUtil.round2(jzGf*measureRate);
-                double qtCost = DoubleUtil.round2(qtFees[2]*fbfxRate);
-                double texCost = DoubleUtil.round2((texTotal+btex)*fbfxRate);
+                double qtCost = DoubleUtil.round2(qtFees[2]*fbfxTotalRate);
+                double indepQt = DoubleUtil.round2((qtFees[0]+qtFees[1])*fbfxTotalRate);
+                double cbrSbCost = DoubleUtil.round2(cbrJzFee*fbfxRate);
                 double totalCost = 0.00;
                 if(f){
-                    totalCost = DoubleUtil.sub(DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,texCost),originalFbrCost);
+                    totalCost = DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,cbrSbCost,-originalFbrCost);
                 } else {
-                    totalCost = DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,texCost); //合计
+                    totalCost = DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,cbrSbCost); //合计
                 }
+                double texCost = DoubleUtil.round2((texTotal+btex)*(totalCost+indepQt)/payableTotal);
+                totalCost = DoubleUtil.add(totalCost,texCost);
                 csJzShare = DoubleUtil.add(csJzShare,measuresFee1,measuresFee2);
                 cs2Share = DoubleUtil.add(cs2Share,measuresFee3);
                 gfJzShare = DoubleUtil.add(gfJzShare,gfCost);
@@ -809,22 +836,26 @@ public class OverheadLineService {
                 double originalCbrCost = originalAzFees[i][1];  //原承包人采购
                 double originalFbrCost = originalAzFees[i][2];  //原发包人采购
                 double originalJxrCost = originalAzFees[i][3];   //原机械费
-                double fbfxRate = originalTotalCost/fbfxFee;//分部分项费用占(建筑分部分项和+安装分部分项和)比例
+                double fbfxRate = originalTotalCost/fbfxAzTotal; //分部分项占建筑分部分项比例
+                double fbfxTotalRate = originalTotalCost/fbfxFee;//分部分项费用占(建筑分部分项和+安装分部分项和)比例
 //                (分部分项直接工程费-分部分项进项税额)占(建筑直接工程费合计-建筑甲供材合计进项税额)比例
                 double measureRate = (zjgcAzFee-originalFbrCost/(1+jxslAz)*jxslAz)/(zjgcAzTotal-fbrAzTotal/(1+jxslAz)*jxslAz);
                 double rgRate = originalRgCost/rgAzTotal;
                 double measuresFee1 = DoubleUtil.round2(azcsFees[0]*measureRate); //措施费一(1)
                 double measuresFee2 = DoubleUtil.round2(azcsFees[1]*rgRate);   //措施费一(2)
-                double measuresFee3 = DoubleUtil.round2(cs2Total*fbfxRate); //措施费二
+                double measuresFee3 = DoubleUtil.round2(azcs2Total*fbfxRate); //措施费二
                 double gfCost = DoubleUtil.round2(azGf*rgRate);
-                double qtCost = DoubleUtil.round2(qtFees[2]*fbfxRate);
-                double texCost = DoubleUtil.round2((texTotal+btex)*fbfxRate);
+                double qtCost = DoubleUtil.round2(qtFees[2]*fbfxTotalRate);
+                double indepQt = DoubleUtil.round2((qtFees[0]+qtFees[1])*fbfxTotalRate);
+                double cbrSbCost = DoubleUtil.round2(cbrAzFee*fbfxRate);
                 double totalCost = 0.00;
                 if(f){
-                    totalCost = DoubleUtil.sub(DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,texCost),originalFbrCost); //合计
+                    totalCost = DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,cbrSbCost,-originalFbrCost);
                 } else {
-                    DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,texCost); //合计
+                    totalCost = DoubleUtil.add(originalTotalCost,measuresFee1,measuresFee2,measuresFee3,gfCost,qtCost,cbrSbCost);
                 }
+                double texCost = DoubleUtil.round2((texTotal+btex)*(totalCost+indepQt)/payableTotal);
+                totalCost = DoubleUtil.add(totalCost,texCost);
                 csAzShare = DoubleUtil.add(csAzShare,measuresFee1,measuresFee2);
                 cs2Share = DoubleUtil.add(cs2Share,measuresFee3);
                 gfAzShare = DoubleUtil.add(gfAzShare,gfCost);
@@ -892,37 +923,6 @@ public class OverheadLineService {
         settlementService.save(dlSettlements,id);
 //        wbs节点对象合并
         jzList.addAll(azList);
-        //承包人设备费直接计入“电缆敷设”中,如“电缆敷设”分部分项工程费为0,则按全部分部分项费用比例分摊。
-        if(cbrTotal != 0.00){
-            boolean dealed = false; //true表示“电缆敷设”不为0
-            for(JkxlDetailFee jkxlDetailFee : jzList){
-                Double totalFee = jkxlDetailFee.getTotalFee();
-                if(jkxlDetailFee.getWbsCode().equals("49320000") && totalFee!=null & totalFee!= 0.00){
-                    jkxlDetailFee.setTotalFee(DoubleUtil.add(totalFee,cbrTotal));
-                    dealed = true;
-                    break;
-                }
-            }
-            if(!dealed){
-                double cbrShare = 0.00;
-                for(JkxlDetailFee fee:jzList){
-                    double rate = fee.getOriginalTotalCost()/fbfxFee;
-                    double cbrFee = DoubleUtil.round2(cbrTotal*rate);
-                    cbrShare = DoubleUtil.add(cbrShare,cbrFee);
-                    fee.setTotalFee(DoubleUtil.add(fee.getTotalFee(),cbrFee));
-                }
-                double cbrDiff = DoubleUtil.sub(cbrTotal,cbrShare);
-                if(cbrDiff!=0.00){
-                    for(JkxlDetailFee fee:jzList){
-                        Double totalFee = fee.getTotalFee();
-                        if(totalFee!=null && totalFee!=0.00){
-                            fee.setTotalFee(DoubleUtil.add(totalFee,cbrDiff));
-                            break;
-                        }
-                    }
-                }
-            }
-        }
 
         //获取未识别费用
         List<JkxlAdjustFee> wsbFees = BashInfo.getWsbFee(total);
@@ -935,7 +935,7 @@ public class OverheadLineService {
                 if(jkxlAdjustFee.getType().contains("减") || jkxlAdjustFee.getType().contains("扣") || jkxlAdjustFee.getType().contains("下浮")){
                     fee = fee* -1;
                 }
-                wsbfee += fee;
+                wsbfee = DoubleUtil.add(wsbfee,fee);
             }
         }
         //计算差额
@@ -943,7 +943,7 @@ public class OverheadLineService {
         for(JkxlDetailFee jkxlDetailFee : jzList){
             tz += jkxlDetailFee.getTotalFee();
         }
-        double gxFee = Math.abs(gcjsFee-tz-qtFees[0]-qtFees[1]-wsbfee);
+        double gxFee = Math.abs(DoubleUtil.add(gcjsFee,-tz,-qtFees[0],-qtFees[1],-wsbfee));
         //将其他费用存入集合
         JkxlDetailFee jkxlDetailFee1 = new JkxlDetailFee();
         JkxlDetailFee jkxlDetailFee2 = new JkxlDetailFee();
@@ -956,11 +956,13 @@ public class OverheadLineService {
         jzList.add(jkxlDetailFee1);
         jzList.add(jkxlDetailFee2);
         overheadLineMapper.saveList(jzList);
-        JkxlAdjustFee jkxlAdjustFee2 = new JkxlAdjustFee();
-        jkxlAdjustFee2.setId(id);
-        jkxlAdjustFee2.setType(BashInfo.CE);
-        jkxlAdjustFee2.setFee(gxFee);
-        feeAdjustService.save(jkxlAdjustFee2);
+        if(gxFee!=0.00){
+            JkxlAdjustFee jkxlAdjustFee2 = new JkxlAdjustFee();
+            jkxlAdjustFee2.setId(id);
+            jkxlAdjustFee2.setType(BashInfo.CE);
+            jkxlAdjustFee2.setFee(gxFee);
+            feeAdjustService.save(jkxlAdjustFee2);
+        }
     }
 
 

+ 108 - 0
src/main/java/com/jeeplus/modules/sg/overheadline/util/DetailFeeUtil.java

@@ -0,0 +1,108 @@
+package com.jeeplus.modules.sg.overheadline.util;
+
+import com.jeeplus.modules.sg.overheadline.entity.JkxlDetailFee;
+
+import java.util.List;
+
+public class DetailFeeUtil {
+
+    /**
+     * 处理节点基本信息,保证上级节点的‘直接工程费’、‘人工’等等费用与它的下级节点相应费用和相等
+     * 处理方式是将上级节点与下级节点相应费用和的差额放入找到的第一个非空子节点。如果下级子节点金额全为空,则直接放到第一个子节点中
+     *
+     * @param detail 节点对象,这里要保证节点及所有子节点对象都不能为空,且都有wbs编码
+     */
+    public static void dealBaseInfo(JkxlDetailFee detail){
+        List<JkxlDetailFee> subNodes = detail.getNodes();
+        if(subNodes!=null && subNodes.size()>0){
+            double total = 0.00;
+            double zjgc = 0.00;
+            double rg = 0.00;
+            double cbr = 0.00;
+            double fbr = 0.00;
+            double jx = 0.00;
+            for(int i=0;i<subNodes.size();i++){
+                JkxlDetailFee node = subNodes.get(i);
+                total = DoubleUtil.add(total,node.getOriginalTotalCost());
+                zjgc = DoubleUtil.add(zjgc,node.getZjgcFee());
+                rg = DoubleUtil.add(rg,node.getOriginalRgCost());
+                cbr = DoubleUtil.add(cbr,node.getOriginalCbrCost());
+                fbr = DoubleUtil.add(fbr,node.getOriginalFbrCost());
+                jx = DoubleUtil.add(jx,node.getOriginalJxCost());
+            }
+            JkxlDetailFee firstNode = subNodes.get(0);
+            firstNode.setOriginalTotalCost(DoubleUtil.add(firstNode.getOriginalTotalCost(),DoubleUtil.sub(detail.getOriginalTotalCost(),total)));
+            firstNode.setZjgcFee(DoubleUtil.add(firstNode.getZjgcFee(),DoubleUtil.sub(detail.getZjgcFee(),zjgc)));
+            firstNode.setOriginalRgCost(DoubleUtil.add(firstNode.getOriginalRgCost(),DoubleUtil.sub(detail.getOriginalRgCost(),rg)));
+            firstNode.setOriginalCbrCost(DoubleUtil.add(firstNode.getOriginalCbrCost(),DoubleUtil.sub(detail.getOriginalCbrCost(),cbr)));
+            firstNode.setOriginalFbrCost(DoubleUtil.add(firstNode.getOriginalFbrCost(),DoubleUtil.sub(detail.getOriginalFbrCost(),fbr)));
+            firstNode.setOriginalJxCost(DoubleUtil.add(firstNode.getOriginalJxCost(),DoubleUtil.sub(detail.getOriginalJxCost(),jx)));
+//            处理完后进行递归
+            for(int i=0;i<subNodes.size();i++){
+                dealBaseInfo(subNodes.get(i));
+            }
+        }
+    }
+
+    /**
+     * 处理节点分本体信息,保证上级节点的‘措施费’、‘规费’等等费用与它的下级节点相应费用和相等
+     * 处理方式是将上级节点与下级节点相应费用和的差额放入找到的第一个非空子节点。如果下级子节点金额全为空,则直接放到第一个子节点中
+     *
+     * @param detail 节点对象,这里要保证节点及所有子节点对象都不能为空,且都有wbs编码,都有值
+     */
+    public static void dealExtraInfo(JkxlDetailFee detail){
+        List<JkxlDetailFee> subNodes = detail.getNodes();
+        if(subNodes!=null && subNodes.size()>0){
+            double csFee1 = 0.00;
+            double csFee2 = 0.00;
+            double csFee3 = 0.00;
+            double qt = 0.00;
+            double gf = 0.00;
+            double cbrSb = 0.00;
+            double tex = 0.00;
+            double total = 0.00;
+            for(int i=0;i<subNodes.size();i++){
+                JkxlDetailFee node = subNodes.get(i);
+                csFee1 = DoubleUtil.add(csFee1,node.getMeasuresFee1());
+                csFee2 = DoubleUtil.add(csFee2,node.getMeasuresFee2());
+                csFee3 = DoubleUtil.add(csFee3,node.getMeasuresFee3());
+                qt = DoubleUtil.add(qt,node.getOtherCost());
+                gf = DoubleUtil.add(gf,node.getFees());
+                cbrSb = DoubleUtil.add(cbrSb,node.getCbrSb());
+                tex = DoubleUtil.add(tex,node.getTex());
+                total = DoubleUtil.add(total,node.getTotalFee());
+            }
+            JkxlDetailFee firstNode = subNodes.get(0);
+            firstNode.setMeasuresFee1(DoubleUtil.add(firstNode.getMeasuresFee1(),detail.getMeasuresFee1(),-csFee1));
+            firstNode.setMeasuresFee2(DoubleUtil.add(firstNode.getMeasuresFee2(),detail.getMeasuresFee2(),-csFee2));
+            firstNode.setMeasuresFee3(DoubleUtil.add(firstNode.getMeasuresFee3(),detail.getMeasuresFee3(),-csFee3));
+            firstNode.setOtherCost(DoubleUtil.add(firstNode.getOtherCost(),detail.getOtherCost(),-qt));
+            firstNode.setFees(DoubleUtil.add(firstNode.getFees(),detail.getFees(),-gf));
+            firstNode.setCbrSb(DoubleUtil.add(firstNode.getCbrSb(),detail.getCbrSb(),-cbrSb));
+            firstNode.setTex(DoubleUtil.add(firstNode.getTex(),detail.getTex(),-tex));
+            firstNode.setTotalFee(DoubleUtil.add(firstNode.getTotalFee(),detail.getTotalFee(),-total));
+//            处理完后进行递归
+            for(int i=0;i<subNodes.size();i++){
+                dealExtraInfo(subNodes.get(i));
+            }
+        }
+    }
+
+    /**
+     * 将节点对象fee,以及fee下所有层级子节点放入list中
+     * @param fee
+     * @param list
+     */
+    public static void addList(JkxlDetailFee fee,List<JkxlDetailFee> list){
+        if(fee!=null){
+            list.add(fee);
+            List<JkxlDetailFee> subNodes = fee.getNodes();
+            if(subNodes!=null&&subNodes.size()>0){
+                for(int i=0;i<subNodes.size();i++){
+                    JkxlDetailFee node = subNodes.get(i);
+                    addList(node,list);
+                }
+            }
+        }
+    }
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1121 - 777
src/main/java/com/jeeplus/modules/sg/substation/service/SubstationService.java


+ 110 - 9
src/main/java/com/jeeplus/modules/sg/substation/util/SubstationInfo.java

@@ -4,6 +4,7 @@ import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.common.utils.excel.ImportExcel;
 import com.jeeplus.common.utils.sg.ExcelUtil;
 import com.jeeplus.modules.sg.overheadline.entity.JkxlDetailFee;
+import com.jeeplus.modules.sg.overheadline.util.DoubleUtil;
 
 import java.lang.reflect.Array;
 import java.util.*;
@@ -41,8 +42,6 @@ public class SubstationInfo {
     public static final String JZMX_KKCLBCZZ= "可控串联补偿装置控制室";
     public static final String JZMX_JZWGBCZZ= "静止无功补偿装置晶闸管阀室";
 
-
-
     public static final String JZMX_PDZZJZ = "配电装置建筑";
     public static final String JZMX_ZBYQXT = "主变压器系统";
     public static final String JZMX_GZJJJC = "构支架及基础";
@@ -51,6 +50,7 @@ public class SubstationInfo {
     public static final String JZMX_FHQ = "防火墙";
     public static final String JZMX_SGYC = "事故油池";
 
+
     public static final String JZMX_JGSBJC = "构架及设备基础";
     public static final String JZMX_1000JGJC = "1000kV构架及基础";
     public static final String JZMX_1000SBZJ = "1000kV设备支架及基础";
@@ -97,6 +97,7 @@ public class SubstationInfo {
     public static final String JZMX_SJ= "深井";
     public static final String JZMX_XSC= "蓄水池";
 
+
     public static final String JZMX_XFXT= "消防系统";
     public static final String JZMX_XFSBF= "消防水泵房";
     public static final String JZMX_YLFS= "雨淋阀室";
@@ -112,6 +113,9 @@ public class SubstationInfo {
     public static final String JZMX_JWS= "警卫室";
     public static final String JZMX_YSBF= "雨水泵房";
 
+
+
+
     public static final String JZMX_ZQXJZ= "站区性建筑";
     public static final String JZMX_CDPZ= "场地平整";
     public static final String JZMX_ZQDLJGC= "站区道路及广场";
@@ -155,6 +159,7 @@ public class SubstationInfo {
     public static final String AZMX_DYDKQ= "低压电抗器";
     public static final String AZMX_JZWGBCZZ= "静止无功补偿装置";
 
+
     public static final String AZMX_KZJZLXT= "控制及直流系统";
     public static final String AZMX_JSJJKXT= "计算机监控系统";
     public static final String AZMX_JDBH= "继电保护";
@@ -274,7 +279,7 @@ public class SubstationInfo {
     public static String[] PDZZALLSTR = {JZMX_ZBYQXT,JZMX_GYDKQXT,JZMX_CLBCXT,JZMX_DYDRQ,JZMX_DYDKQ,JZMX_JZWGBC,JZMX_ZYBYQXT,JZMX_BLZT,JZMX_DLGD,JZMX_LGJDP,JZMX_PDZZQY,
             JZMX_1000JGJC,JZMX_1000SBZJ,JZMX_750JGJC,JZMX_750SBZJ,JZMX_500JGJC,JZMX_500SBZJ,JZMX_330JGJC,JZMX_330SBZJ,JZMX_220JGJC,JZMX_220SBZJ,
             JZMX_110JGJC,JZMX_110SBZJ,JZMX_66JGJC,JZMX_66SBZJ,JZMX_35JGJC,JZMX_35SBZJ,JZMX_10JGJC,JZMX_10SBZJ,JZMX_GZJJJC, JZMX_ZBYQJC,JZMX_ZBYQYK,JZMX_FHQ,JZMX_SGYC,JZMX_JGSBJC
-            ,JZMX_CLBCSBJC,JZMX_CLBCSBJG,JZMX_SBZJJJC,JZMX_JZWGBCJC,JZMX_JZWGBCJC,JZMX_ZYBYQSBJC
+            ,JZMX_CLBCSBJC,JZMX_CLBCSBJG,JZMX_SBZJJJC,JZMX_JZWGBCJC,JZMX_ZYBYQSBJC
     };
 
 
@@ -530,7 +535,13 @@ public class SubstationInfo {
 
 
     /**
-     * 获取基础数据
+     * 节点的基础数据  其中“直接工程费”从 importExcel1中找到值为str行获取。“合计”、“人工费”,“投标人采购”,“招标人采购”、“机械费”从importExcel
+     * 中找到值包含str行获取
+     * @param importExcel 建筑/安装工程量清单计价表
+     * @param importExcel1 建筑/安装工程费用汇总表
+     * @param wbs
+     * @param str
+     * @return
      */
     public static JkxlDetailFee getBashInfo(ImportExcel importExcel,ImportExcel importExcel1,String wbs,String str){
         double[] doubles = ExcelUtil.getBashArray(importExcel,str,2,new int[]{12,13, 14, 15, 17});
@@ -570,10 +581,18 @@ public class SubstationInfo {
     }
 
     /**
-     *获得基础数据,工程费分摊
+     *
+     * @param importExcel 建筑/安装工程量清单计价表
+     * @param importExcel1 建筑/安装工程费用汇总表
+     * @param wbs  某个节点及其子节点wbs
+     * @param str  某个节点及其子节点名称
+     * @param types
+     * @return
      */
     public static List<JkxlDetailFee> getBashInfos(ImportExcel importExcel,ImportExcel importExcel1,String[] wbs,String[] str ,String types){
+//        从清单计价表获取所有节点人工费等
          double[][] doubles = ExcelUtil.getBashArray(importExcel,str,2,new int[]{12,13, 14, 15, 17});
+//        获取父节点的直接工程费
          double d = ExcelUtil.getDouble(importExcel1,str[0],1,3);  //直接工程费
          String index = ExcelUtil.getIndex(importExcel,str[0],2);    //获取角标
          int s = 1;
@@ -654,11 +673,14 @@ public class SubstationInfo {
     }
 
 
-
-
-
     /**
-     * 建筑安装基础数据
+     * 建筑安装总节点的基础数据  其中“合计”,“直接工程费”从 importExcel1中“合计”行获取。“人工费”,“投标人采购”,“招标人采购”、“机械费”从importExcel
+     * 获取
+     * @param importExcel 建筑/安装工程量清单计价表
+     * @param importExcel1 建筑/安装工程费用汇总表
+     * @param wbs
+     * @param str
+     * @return
      */
     public static JkxlDetailFee getTolalInfo(ImportExcel importExcel,ImportExcel importExcel1,String wbs,String str){
         double[] doubles = ExcelUtil.getDoubleArray(importExcel,str,2,new int[]{12,13, 14, 15, 17});
@@ -675,6 +697,8 @@ public class SubstationInfo {
         return jkxlDetailFee;
     }
 
+
+
     /**
      * 配电装置建筑基础数据
      */
@@ -1091,6 +1115,75 @@ public class SubstationInfo {
 
     /**
      * 获取措施费2中的建筑措施费
+     * 代码逻辑:先确定建筑措施范围,先查找小计值,如果无小计值,则获取‘一’,‘二’行值相加
+     *
+     */
+    public static double getCs2JzFee(ImportExcel importExcel){
+        int lastRow = importExcel.getLastDataRowNum();
+        for(int i=0;i<lastRow;i++){
+            String type = importExcel.getValue(i+1,2);
+            if(type.equals(CS_AZ)){
+                lastRow = i+1;
+                break;
+            }
+        }
+        for(int i=0;i<lastRow;i++){
+            String type = importExcel.getValue(i+1,0);
+            if(type.equals(QT_XJ)){
+                double d = importExcel.getDouble(i+1,10);
+                return d;
+            }
+        }
+        double cs = 0.00;
+        for(int i=0;i<lastRow;i++){
+            String type = importExcel.getValue(i+1,1);
+            if(type.equals("一")||type.equals("二")){
+               double d = importExcel.getDouble(i+1,10);
+               cs = DoubleUtil.add(cs,d);
+            }
+        }
+        return cs;
+    }
+
+    /**
+     * 获取措施费2中 安装措施费
+     * 代码逻辑:先查找‘安装措施项目’,若不存在则返回0,存在则返回小计,或‘一’+‘二’行数据
+     */
+    public static double getCs2AzFee(ImportExcel importExcel){
+        int startRow = -1;
+        int lastRow = importExcel.getLastDataRowNum();
+        for(int i=0;i<lastRow;i++){
+            String type = importExcel.getValue(i+1,2);
+            if(type.equals(CS_AZ)){
+                startRow = i+1;
+                break;
+            }
+        }
+        if(startRow==-1){
+            return 0.00;
+        }
+        for(int i=startRow;i<lastRow;i++){
+            String type = importExcel.getValue(i+1,0);
+            if(type.equals(QT_XJ)){
+                double d = importExcel.getDouble(i+1,10);
+                return d;
+            }
+        }
+        double cs = 0.00;
+        for(int i=0;i<lastRow;i++){
+            String type = importExcel.getValue(i+1,1);
+            if(type.equals("一")||type.equals("二")){
+                double d = importExcel.getDouble(i+1,10);
+                cs = DoubleUtil.add(cs,d);
+            }
+        }
+        return cs;
+    }
+
+
+
+    /**
+     * 获取措施费2中的建筑措施费
      * 代码逻辑:如果第一列有“小计”返回该列值,如果没有继续判断,如果第三列没有“建筑措施项目”
      * 返回0,如果有返回第二列文字为“一”行的值
      */
@@ -1155,6 +1248,14 @@ public class SubstationInfo {
     }
 
 
+    /**
+     *
+     * @param importExcel  清单计价表
+     * @param st   角标
+     * @param strs  节点文字
+     * @param types  父节点类型 1:节点属于主要生产工程  2:节点属于辅助生产工程
+     * @return
+     */
     public static double[][] getUnidentification(ImportExcel importExcel,String st,String[] strs,String types){
         int startRow = 0;
         int lastRow = importExcel.getLastDataRowNum();

+ 677 - 0
src/main/java/com/jeeplus/modules/sg/substation/util/SubstationUtil.java

@@ -0,0 +1,677 @@
+package com.jeeplus.modules.sg.substation.util;
+
+import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.common.utils.excel.ImportExcel;
+import com.jeeplus.common.utils.sg.ExcelUtil;
+import com.jeeplus.modules.sg.overheadline.entity.JkxlDetailFee;
+import com.jeeplus.modules.sg.overheadline.util.DoubleUtil;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class SubstationUtil {
+
+    //节点归属,表示节点为主要生产工程下节点
+    public static final Integer NODE_BELONG_ZY = 1;
+    //节点归属,表示节点为辅助生产工程下节点
+    public static final Integer NODE_BELONG_FZ = 2;
+    //节点归属,表示节点为与站点有关的单项工程下节点
+    public static final Integer NODE_BELONG_DX = 3;
+//    角标正则表达式
+    public static final String MARK_EXP = "(\\d|\\.)+";
+    /*
+    下面节点名称数组都是以结算书中结构进行组织,名称后缀有_HUI表示包含父节点
+     */
+    //主要生产建筑
+    public static final String MADE_WBS_JDQS = "JDQS";   //结算书中继电器室节点虚拟wbs
+    public static final String MADE_WBS_PDZZS = "PDZZS";  //结算书中配电装置室节点虚拟wbs
+    public static final String[] WBS_JZ_ZYSCJZ_HUI =  {"21110000","21111000","2111N000","2111P000","2111Q000","2111R000",MADE_WBS_JDQS,MADE_WBS_PDZZS};
+    public static final String[] NODE_JZ_ZYSCJZ_HUI = {"主要生产建筑","主控通信楼","固定串联补偿装置控制室","可控高压电抗器晶闸管阀室","可控串联补偿装置控制室",
+            "静止无功补偿装置晶闸管阀室","继电器室","配电装置室"};
+    public static final String[] WBS_JZ_JDQS = {"21112000","21113000","21114000","21115000","21116000","21117000","21118000","21119000","2111A000"};
+    public static final String[] NODE_JZ_JDQS = {"1000kV继电器室","750kV继电器室","500kV继电器室","330kV继电器室","220kV继电器室","110kV继电器室","66kV继电器室",
+            "35kV继电器室","10kV继电器室"};
+    public static final String[] WBS_JZ_PDZZS = {"2111B000","2111C000","2111D000","2111F000","2111G000","2111H000","2111J000","2111K000", "2111L000","2111M000"};
+    public static final String[] NODE_JZ_PDZZS =  {"站用配电装置室","1000kV配电装置室","750kV配电装置室","500kV配电装置室","330kV配电装置室","220kV配电装置室",
+            "110kV配电装置室","66kV配电装置室","35kV配电装置室","10kV配电装置室"};
+    //配电装置建筑
+    public static final String MADE_WBS_GJJSBJC = "GJJSBJC";//结算书中构架及设备基础节点虚拟wbs
+    public static final String[] WBS_JZ_PDZZJZ_HUI = {"21120000","21121000","2112B000","2112C000","2112D000","2112F000","2112G000","2112H000","2112J000","2112K000","2112L000","2112M000",MADE_WBS_GJJSBJC};
+    public static final String[] NODE_JZ_PDZZJZ_HUI =  {"配电装置建筑","主变压器系统","高压电抗器系统","串联补偿系统","低压电容器","低压电抗器","静止无功补偿装置",
+            "站用变压器系统","避雷针塔","电缆沟道","栅栏及地坪","配电装置区域地面封闭","构架及设备基础"};
+    public static final String[] WBS_JZ_ZBYQXT = {"21121100","21121200","21121300","21121400","21121500"};
+    public static final String[] NODE_JZ_ZBYQXT = {"构支架及基础","主变压器设备基础","主变压器油坑及卵石","防火墙","事故油池"};
+    public static final String[] WBS_JZ_GYDKQXT = {"2112B100","2112B200","2112B300","2112B400","2112B500"};
+    public static final String[] NODE_JZ_GYDKQXT = {"构支架及基础","高压电抗器设备基础","高抗油池及卵石","防火墙","事故油池"};
+    public static final String[] WBS_JZ_CLBCXT = {"2112C100","2112C200","2112C300","2112C400"};
+    public static final String[] NODE_JZ_CLBCXT = {"串联补偿设备平台基础","串联补偿设备平台结构","构支架及基础","设备支架及基础"};
+    public static final String[] WBS_JZ_JZWGBCZZ = {"2112G100","2112G200"};
+    public static final String[] NODE_JZ_JZWGBCZZ = {"构支架及基础","静止无功补偿装置设备基础"};
+    public static final String[] WBS_JZ_ZYBYQXT = {"2112H100","2112H200"};
+    public static final String[] NODE_JZ_ZYBYQXT = {"站用变压器设备基础","防火墙"};
+    public static final String[] WBS_JZ_GJJSBJC = {"21122100","21122200","21123100","21123200","21124100","21124200","21125100","21125200","21126100","21126200","21127100","21127200"
+            ,"21128100","21128200","21129100","21129200","2112A100","2112A200"};
+    public static final String[] NODE_JZ_GJJSBJC = {"1000kV构架及基础","1000kV设备支架及基础","750kV构架及基础","750kV设备支架及基础","500kV构架及基础","500kV设备支架及基础",
+            "330kV构架及基础","330kV设备支架及基础","220kV构架及基础","220kV设备支架及基础","110kV构架及基础","110kV设备支架及基础",
+            "66kV构架及基础","66kV设备支架及基础","35kV构架及基础","35kV设备支架及基础","10kV构架及基础","10kV设备支架及基础"};
+    //供水系统建筑
+    public static final String[] WBS_JZ_GSXTJZ_HUI = {"21130000","21131000","21132000","21133000","21134000","21135000"};
+    public static final String[] NODE_JZ_GSXTJZ_HUI =  {"供水系统建筑","站区供水管道","供水系统设备","综合水泵房","深井","蓄水池"};
+    //消防系统
+    public static final String[] WBS_JZ_XFXT_HUI = {"21140000","21141000","21142000","21143000","21144000","21145000","21146000"};
+    public static final String[] NODE_JZ_XFXT_HUI = {"消防系统","消防水泵房","雨淋阀室","站区消防管道","消防器材","特殊消防系统","消防水池"};
+    //辅助生产建筑
+    public static final String[] WBS_JZ_FZSCJZ_HUI = {"21210000","21211000","21212000","21213000"};
+    public static final String[] NODE_JZ_FZSCJZ_HUI = {"辅助生产建筑","综合楼","警卫室","雨水泵房"};
+    //站区性建筑
+    public static final String[] WBS_JZ_ZQXJZ_HUI =  {"21220000","21221000","21222000","21223000","21224000"};
+    public static final String[] NODE_JZ_ZQXJZ_HUI = {"站区性建筑","场地平整","站区道路及广场","站区排水","围墙及大门"};
+    //特殊构建物
+    public static final String[] WBS_JZ_TSGZW_HUI = {"21230000","21231000","21232000","21233000"};
+    public static final String[] NODE_JZ_TSGZW_HUI = {"特殊构筑物","挡土墙及挡水墙","防洪排水沟","护坡"};
+    //站区绿化
+    public static final String WBS_JZ_ZQLH = "21240000";
+    public static final String NODE_JZ_ZQLH = "站区绿化";
+//    与站址相关单项工程
+    public static final String[] WBS_JZ_DXGC_HUI = {"2130000","21310000","21320000","21330000","21340000","21350000","21360000"};
+    public static final String[] NODE_JZ_DXGC_HUI = {"与站址有关的单项工程","地基处理","站外道路","站外水源","站外排水","施工降水","临时工程"};
+
+
+    //主变压器系统
+    public static final String[] WBS_AZ_ZBYQXT_HUI = {"23110000","23111000"};
+    public static final String[] NODE_AZ_ZBYQXT_HUI = {"主变压器系统","主变压器"};
+    //配电装置
+    public static final String[] WBS_AZ_PDZZ_HUI = {"23120000","23121000","23122000"};
+    public static final String[] NODE_AZ_PDZZ_HUI = {"配电装置","屋内配电装置","屋外配电装置"};
+    //无功补偿
+    public static final String[] WBS_AZ_WGBC_HUI = {"23130000","23131000","23132000","23133000","23134000","23135000"};
+    public static final String[] NODE_AZ_WGBC_HUI = {"无功补偿","高压电抗器","串联补偿装置","低压电容器","低压电抗器","静止无功补偿装置"};
+    public static final String[] WBS_AZ_GYDKQ = {"23131100","23131200"};
+    public static final String[] NODE_AZ_GYDKQ = {"固定高压电抗器","可控高压电抗器"};
+    public static final String[] WBS_AZ_CLBCZZ = {"23132100","23132200"};
+    public static final String[] NODE_AZ_CLBCZZ = {"固定串联补偿装置","可控串联补偿装置"};
+    //控制及直流系统
+    public static final String MADE_WBS_KZZL = "KZZL";   //结算书中辅助设备与设施节点虚拟wbs
+    public static final String[] WBS_AZ_KZZL_HUI = {"23140000","23141000","23142000","23143000","23144000","23145000",MADE_WBS_KZZL};
+    public static final String[] NODE_AZ_KZZL_HUI =    {"控制及直流系统","计算机监控系统","继电保护","直流系统及不间断电源","智能辅助控制系统","在线监测系统","辅助设备与设施"};
+    //站用电系统
+    public static final String[] WBS_AZ_ZYDXT_HUI = {"23150000","23151000","23152000","23153000"};
+    public static final String[] NODE_AZ_ZYDXT_HUI = {"站用电系统","站用变压器","站用配电装置","站区照明"};
+    //电缆及接地
+    public static final String[] WBS_AZ_DLJJD_HUI = {"23160000","23161000","23162000"};
+    public static final String[] NODE_AZ_DLJJD_HUI = {"电缆及接地","全站电缆","全站接地"};
+    public static final String[] WBS_AZ_QZDL = {"23161100","23161200","23161300","23161400"};
+    public static final String[] NODE_AZ_QZDL = {"电力电缆","控制电缆","电缆辅助设施","电缆防火"};
+    //通信及运动系统
+    public static final String[] WBS_AZ_TXJYDXT_HUI = {"23170000","23171000","23172000"};
+    public static final String[] NODE_AZ_TXJYDXT_HUI = {"通信及远动系统","通信系统","远动及计费系统"};
+    //全站调试
+    public static final String[] WBS_AZ_QZTS_HUI = {"23180000","23181000","23182000","23183000"};
+    public static final String[] NODE_AZ_QZTS_HUI = {"全站调试","分系统调试","整套启动调试","特殊项目调试"};
+//    辅助生产工程
+    public static final String[] WBS_AZ_FZSCGC_HUI = {"23200000","23210000","23220000","23230000"};
+    public static final String[] NODE_AZ_FZSCGC_HUI ={"辅助生产工程","检修及修配设备","试验设备","油及SF6处理设备"};
+    //站外电源
+    public static final String[] WBS_AZ_ZWDY_HUI = {"23310000","23311000","23312000"};;
+    public static final String[] NODE_AZ_ZWDY_HUI =  {"站外电源","站外电源线路","站外电源间隔"};
+    //站外通信
+    public static final String[] WBS_AZ_ZWTX_HUI = {"23320000","23321000"};;
+    public static final String[] NODE_AZ_ZWTX_HUI = {"站外通信","站外通信线路"};
+
+
+
+
+    /**
+     * 建筑安装总节点的基础数据
+     * 其中“直接工程费”从 hz“合计”行获取。“人工费”,“投标人采购”,“招标人采购”、“机械费”qd获取
+     *
+     * @param qd 建筑/安装工程量清单计价表
+     * @param hz 建筑/安装工程费用汇总表
+     * @param wbs 总节点wbs编码
+     * @param str 总结点名称
+     * @return
+     */
+    public static JkxlDetailFee getTotalBaseInfo(ImportExcel qd,ImportExcel hz,String wbs,String str){
+        double[] doubles = ExcelUtil.getDoubleArray(qd,str,2,new int[]{12,13, 14, 15, 17});
+        double d = ExcelUtil.getDouble(hz,SubstationInfo.QT_HJ,0,3);  //直接工程费
+        if(d == 0.00){
+            return null;
+        }
+        JkxlDetailFee jkxlDetailFee = new JkxlDetailFee();
+        jkxlDetailFee.setWbsCode(wbs);
+        jkxlDetailFee.setOriginalTotalCost(doubles[0]);
+        jkxlDetailFee.setOriginalRgCost(doubles[1]);
+        jkxlDetailFee.setOriginalFbrCost(doubles[3]);
+        jkxlDetailFee.setOriginalCbrCost(doubles[2]);
+        jkxlDetailFee.setOriginalJxCost(doubles[4]);
+        jkxlDetailFee.setZjgcFee(d);
+        return jkxlDetailFee;
+    }
+
+
+    /**
+     * 节点的基础数据,若该分部分项节点在汇总表找不到直接工程费,则判断此分部分项为空
+     * 其中“直接工程费”从hz中找到值为str行获取。“合计”、“人工费”,“投标人采购”,“招标人采购”、“机械费”从qd
+     * 中找到值包含str行获取
+     * 注意:这里查找的节点数据,一定是清单表和汇总表中都有的
+     * @param qd 建筑/安装工程量清单计价表
+     * @param hz 建筑/安装工程费用汇总表
+     * @param wbs 节点wbs编码
+     * @param str 节点名称
+     * @return
+     */
+    public static JkxlDetailFee getBaseInfo(ImportExcel qd,ImportExcel hz,String wbs,String str){
+        double[] doubles = ExcelUtil.getBashArray(qd,str,2,new int[]{12,13, 14, 15, 17});
+        double d = ExcelUtil.getDouble(hz,str,1,3);  //直接工程费
+        if(d == 0.00){
+            return null;
+        }
+        JkxlDetailFee jkxlDetailFee = new JkxlDetailFee();
+        jkxlDetailFee.setWbsCode(wbs);
+        jkxlDetailFee.setOriginalTotalCost(doubles[0]);
+        jkxlDetailFee.setOriginalRgCost(doubles[1]);
+        jkxlDetailFee.setOriginalFbrCost(doubles[3]);
+        jkxlDetailFee.setOriginalCbrCost(doubles[2]);
+        jkxlDetailFee.setOriginalJxCost(doubles[4]);
+        jkxlDetailFee.setZjgcFee(d);
+        return jkxlDetailFee;
+    }
+
+
+    /**
+     * 获取多个节点的基础数据
+     * @param qd 建筑/安装工程量清单计价表
+     * @param hz 建筑/安装工程费用汇总表
+     * @param wbs 节点wbs编码
+     * @param nodes 节点名称
+     * @return
+     */
+    public static List<JkxlDetailFee> getBaseInfos(ImportExcel qd,ImportExcel hz,String[] wbs,String[] nodes){
+        List<JkxlDetailFee> fees = new ArrayList<>();
+        for(int i=0;i<wbs.length;i++){
+            JkxlDetailFee fee = getBaseInfo(qd,hz,wbs[i],nodes[i]);
+            if(fee != null){
+                fees.add(fee);
+            }
+        }
+        return fees;
+    }
+
+
+    /**
+     *获取mainFee所有子节点基础数据,若无子节点则返回父节点基础数据。
+     *
+     * @param qd   清单计价表
+     * @param mainFee   父节点
+     * @param wbs  子节点wbs编码
+     * @param nodes  子节点名称
+     * @param type   节点归属,1:节点属于主要生产工程  2:节点属于辅助生产工程 3:与站址有关的单项工程
+     * @return
+     */
+    public static void getSubBaseInfos(ImportExcel qd,JkxlDetailFee mainFee,String mainNode,String[] wbs,String[] nodes,Integer type){
+        if(mainFee == null){
+            return ;
+        }
+        String cornerMark = getNodeMark(qd,mainNode,2);
+        if(cornerMark==null){
+            throw new RuntimeException(getWrongMessage(qd));
+        }
+        List<String> subNodes = getSubNodes(qd,cornerMark,2,type);
+        List<String> leftNodes = new ArrayList<>(subNodes);
+        if(subNodes!=null&&subNodes.size()>0){
+//            这里用map处理是因为下文用了contain方法,防止出现多个结算书节点匹配上同一个标准节点名称,后者替换前者额情况出现
+            Map<Integer,JkxlDetailFee> map = new HashMap<>();
+            double totalSum = 0.00;
+            for(int i=0;i<subNodes.size();i++){
+                String node = subNodes.get(i);
+                for(int j=0;j<nodes.length;j++){
+                    if(node.contains(nodes[j])){
+                        JkxlDetailFee fee = map.get(j);
+                        if(fee==null){
+                            fee = new JkxlDetailFee(wbs[j]);
+                            map.put(j,fee);
+                        }
+                        double[] doubles = ExcelUtil.getDoubleArray(qd,node,2,new int[]{12,13, 14, 15, 17});
+                        fee.setOriginalTotalCost(DoubleUtil.add(fee.getOriginalTotalCost(),doubles[0]));
+                        fee.setOriginalRgCost(DoubleUtil.add(fee.getOriginalRgCost(),doubles[1]));
+                        fee.setOriginalCbrCost(DoubleUtil.add(fee.getOriginalCbrCost(),doubles[2]));
+                        fee.setOriginalFbrCost(DoubleUtil.add(fee.getOriginalFbrCost(),doubles[3]));
+                        fee.setOriginalJxCost(DoubleUtil.add(fee.getOriginalJxCost(),doubles[4]));
+                        totalSum = DoubleUtil.add(totalSum,doubles[0]);
+                        leftNodes.remove(node);
+                        break;
+                    }
+                }
+            }
+            if(map.isEmpty()){
+                throw new RuntimeException(getWrongMessage(qd));
+            }
+            List<JkxlDetailFee> subFees = new ArrayList<>();
+            for(JkxlDetailFee fee:map.values()){
+                subFees.add(fee);
+            }
+//            若结算书子节点存在与标准节点名对应不上的将值放入第一个节点
+            if(leftNodes.size()>0){
+                JkxlDetailFee firstSubFee = subFees.get(0);
+                for(int i=0;i< leftNodes.size();i++){
+                    String node = leftNodes.get(i);
+                    double[] doubles = ExcelUtil.getDoubleArray(qd,node,2,new int[]{12,13, 14, 15, 17});
+                    firstSubFee.setOriginalTotalCost(DoubleUtil.add(firstSubFee.getOriginalTotalCost(),doubles[0]));
+                    firstSubFee.setOriginalRgCost(DoubleUtil.add(firstSubFee.getOriginalRgCost(),doubles[1]));
+                    firstSubFee.setOriginalCbrCost(DoubleUtil.add(firstSubFee.getOriginalCbrCost(),doubles[2]));
+                    firstSubFee.setOriginalFbrCost(DoubleUtil.add(firstSubFee.getOriginalFbrCost(),doubles[3]));
+                    firstSubFee.setOriginalJxCost(DoubleUtil.add(firstSubFee.getOriginalJxCost(),doubles[4]));
+                    totalSum = DoubleUtil.add(totalSum,doubles[0]);
+                }
+            }
+//            子节点的直接工程费,用父节点直接工程费根据分部分项费用进行分摊,这里没有做子节点差额处理
+            for(int i=0;i<subFees.size();i++){
+                JkxlDetailFee fee = subFees.get(i);
+                fee.setZjgcFee(DoubleUtil.round2(mainFee.getZjgcFee()*fee.getOriginalTotalCost()/totalSum));
+            }
+            mainFee.setNodes(subFees);
+        }
+    }
+
+
+
+    /**
+     *获取节点及其子节点基础数据,若无子节点则返回父节点基础数据。
+     *
+     * @param qd   清单计价表
+     * @param hz   汇总表
+     * @param wbs  父节点及其子节点wbs编码,其中父节点wbs放在第一个
+     * @param nodes  父节点及其子节点名称,其中父节点放在第一个
+     * @param type   节点归属,1:节点属于主要生产工程  2:节点属于辅助生产工程 3:与站址有关的单项工程
+     * @return
+     */
+    public static JkxlDetailFee getSubBaseInfos(ImportExcel qd,ImportExcel hz,String[] wbs,String[] nodes,Integer type){
+        JkxlDetailFee mainFee = getBaseInfo(qd,hz,wbs[0],nodes[0]);
+        if(mainFee == null){
+            return null;
+        }
+        String[] subWbs = Arrays.copyOfRange(wbs,1,wbs.length);
+        String[] subNodes = Arrays.copyOfRange(nodes,1,nodes.length);
+        getSubBaseInfos(qd,mainFee,nodes[0],subWbs,subNodes,type);
+        return mainFee;
+    }
+
+
+    /**
+     * 获取建筑‘主要生产建筑’及其子节点基础数据
+     * @param jzqd  建筑工程量清单计价表
+     * @param jzhz  建筑工程汇总表
+     * @return
+     */
+    public static JkxlDetailFee getZyscjz(ImportExcel jzqd, ImportExcel jzhz){
+        JkxlDetailFee mainFee = getSubBaseInfos(jzqd,jzhz,WBS_JZ_ZYSCJZ_HUI,NODE_JZ_ZYSCJZ_HUI,NODE_BELONG_ZY);
+        if(mainFee!=null){
+            List<JkxlDetailFee> subFees = mainFee.getNodes();
+            List<JkxlDetailFee> addFees = new ArrayList<>();
+            if(subFees!=null&&subFees.size()>0){
+                for(int i=0;i<subFees.size();i++){
+                    JkxlDetailFee fee = subFees.get(i);
+                    if(fee.getWbsCode().equals(MADE_WBS_JDQS)){
+                        getSubBaseInfos(jzqd,fee,"继电器室",WBS_JZ_JDQS,NODE_JZ_JDQS,NODE_BELONG_ZY);
+                        addFees.addAll(fee.getNodes());
+                        subFees.remove(fee);
+                        continue;
+                    }
+                    if(fee.getWbsCode().equals(MADE_WBS_PDZZS)){
+                        getSubBaseInfos(jzqd,fee,"配电装置室",WBS_JZ_PDZZS,NODE_JZ_PDZZS,NODE_BELONG_ZY);
+                        addFees.addAll(fee.getNodes());
+                        subFees.remove(fee);
+                    }
+                }
+            }
+            subFees.addAll(addFees);
+        }
+        return mainFee;
+    }
+
+    /**
+     * 获取建筑‘配电装置建筑’及其子节点基础数据
+     * @param jzqd  建筑工程量清单计价表
+     * @param jzhz  建筑工程汇总表
+     * @return
+     */
+    public static JkxlDetailFee getPdzzjz(ImportExcel jzqd, ImportExcel jzhz){
+        JkxlDetailFee mainFee = getSubBaseInfos(jzqd,jzhz,WBS_JZ_PDZZJZ_HUI,NODE_JZ_PDZZJZ_HUI,NODE_BELONG_ZY);
+        if(mainFee!=null){
+            List<JkxlDetailFee> subFees = mainFee.getNodes();
+            if(subFees!=null&&subFees.size()>0){
+                List<JkxlDetailFee> addFees = new ArrayList<>();
+                for(int i=0;i<subFees.size();i++){
+                    JkxlDetailFee fee = subFees.get(i);
+                    if(fee.getWbsCode().equals("21121000")){
+                        getSubBaseInfos(jzqd,fee,"主变压器系统",WBS_JZ_ZBYQXT,NODE_JZ_ZBYQXT,NODE_BELONG_ZY);
+                        continue; //处理主变压器系统子节点
+                    }
+                    if(fee.getWbsCode().equals("2112B000")){
+                        getSubBaseInfos(jzqd,fee,"高压电抗器系统",WBS_JZ_GYDKQXT,NODE_JZ_GYDKQXT,NODE_BELONG_ZY);
+                        continue; //处理高压电抗器系统子节点
+                    }
+                    if(fee.getWbsCode().equals("2112C000")){
+                        getSubBaseInfos(jzqd,fee,"串联补偿系统",WBS_JZ_CLBCXT,NODE_JZ_CLBCXT,NODE_BELONG_ZY);
+                        continue; //处理串联补偿系统子节点
+                    }
+                    if(fee.getWbsCode().equals("2112G000")){
+                        getSubBaseInfos(jzqd,fee,"静止无功补偿装置",WBS_JZ_JZWGBCZZ,NODE_JZ_JZWGBCZZ,NODE_BELONG_ZY);
+                        continue; //处理静止无功补偿装置子节点
+                    }
+                    if(fee.getWbsCode().equals("2112H000")){
+                        getSubBaseInfos(jzqd,fee,"站用变压器系统",WBS_JZ_ZYBYQXT,NODE_JZ_ZYBYQXT,NODE_BELONG_ZY);
+                        continue; //处理站用变压器系统子节点
+                    }
+                    if(fee.getWbsCode().equals(MADE_WBS_GJJSBJC)){
+                        getSubBaseInfos(jzqd,fee,"构架及设备基础",WBS_JZ_GJJSBJC,NODE_JZ_GJJSBJC,NODE_BELONG_ZY);
+                        subFees.remove(fee);
+                        addFees = gjjsbjcDeal(fee.getNodes()); //处理构架及设备基础
+                    }
+                }
+                subFees.addAll(addFees);
+            }
+        }
+        return mainFee;
+    }
+
+    /**
+     * 获取建筑‘与站址有关的单项工程’及其子节点基础数据
+     * @param jzqd  建筑工程量清单计价表
+     * @param jzhz  建筑工程汇总表
+     * @return
+     */
+    public static JkxlDetailFee getDxgc(ImportExcel jzqd, ImportExcel jzhz){
+        JkxlDetailFee mainFee = getBaseInfo(jzqd,jzhz,WBS_JZ_DXGC_HUI[0],NODE_JZ_DXGC_HUI[0]);
+        if(mainFee!=null){
+            String[] subWbs = Arrays.copyOfRange(WBS_JZ_DXGC_HUI,1,WBS_JZ_DXGC_HUI.length);
+            String[] subNodes = Arrays.copyOfRange(NODE_JZ_DXGC_HUI,1,NODE_JZ_DXGC_HUI.length);
+            List<JkxlDetailFee> nodes = getBaseInfos(jzqd,jzhz,subWbs,subNodes);
+            mainFee.setNodes(nodes);
+        }
+        return mainFee;
+    }
+
+
+
+    /**
+     * 获取安装‘无功补偿’及其子节点基础数据
+     * @param azqd  安装工程量清单计价表
+     * @param azhz  安装工程汇总表
+     * @return
+     */
+    public static JkxlDetailFee getWgbc(ImportExcel azqd, ImportExcel azhz){
+        JkxlDetailFee mainFee = getSubBaseInfos(azqd,azhz,WBS_AZ_WGBC_HUI,NODE_AZ_WGBC_HUI,NODE_BELONG_ZY);
+        if(mainFee!=null){
+            List<JkxlDetailFee> subFees = mainFee.getNodes();
+            if(subFees!=null&&subFees.size()>0){
+                for(int i=0;i<subFees.size();i++){
+                    JkxlDetailFee fee = subFees.get(i);
+                    if(fee.getWbsCode().equals("23131000")){
+                        getSubBaseInfos(azqd,fee,"高压电抗器",WBS_AZ_GYDKQ,NODE_AZ_GYDKQ,NODE_BELONG_ZY);
+                        continue;
+                    }
+                    if(fee.getWbsCode().equals("23132000")){
+                        getSubBaseInfos(azqd,fee,"串联补偿装置",WBS_AZ_CLBCZZ,NODE_AZ_CLBCZZ,NODE_BELONG_ZY);
+                    }
+                }
+            }
+        }
+        return mainFee;
+    }
+
+    /**
+     * 获取安装‘控制及直流系统’及其子节点基础数据
+     * @param azqd  安装工程量清单计价表
+     * @param azhz  安装工程汇总表
+     * @return
+     */
+    public static JkxlDetailFee getKzzl(ImportExcel azqd, ImportExcel azhz){
+        JkxlDetailFee mainFee = getSubBaseInfos(azqd,azhz,WBS_AZ_KZZL_HUI,NODE_AZ_KZZL_HUI,NODE_BELONG_ZY);
+        if(mainFee!=null){
+            List<JkxlDetailFee> subFees = mainFee.getNodes();
+            int index = -1;
+            if(subFees!=null&&subFees.size()>0){
+                for(int i=0;i<subFees.size();i++){
+                    JkxlDetailFee fee = subFees.get(i);
+                    if(fee.getWbsCode().equals(MADE_WBS_KZZL)){
+                        index = i;
+                    }
+                }
+//                表示结算书有额外的节点“辅助设备与设施”
+                if(index != -1){
+                    JkxlDetailFee extraFee = subFees.get(index);
+                    subFees.remove(index);
+//                    如果只有这个额外节点,就把数据放在“在线监测系统”
+                    if(subFees.size()==0){
+                        JkxlDetailFee fee = new JkxlDetailFee("23145000");
+                        subFees.add(fee);
+                    }
+                    JkxlDetailFee addedFee = subFees.get(0);
+                    addedFee.setOriginalTotalCost(DoubleUtil.add(addedFee.getOriginalTotalCost(),extraFee.getOriginalTotalCost()));
+                    addedFee.setOriginalRgCost(DoubleUtil.add(addedFee.getOriginalRgCost(),extraFee.getOriginalRgCost()));
+                    addedFee.setOriginalCbrCost(DoubleUtil.add(addedFee.getOriginalCbrCost(),extraFee.getOriginalCbrCost()));
+                    addedFee.setOriginalFbrCost(DoubleUtil.add(addedFee.getOriginalFbrCost(),extraFee.getOriginalFbrCost()));
+                    addedFee.setOriginalJxCost(DoubleUtil.add(addedFee.getOriginalJxCost(),extraFee.getOriginalJxCost()));
+                    addedFee.setZjgcFee(DoubleUtil.add(addedFee.getZjgcFee(),extraFee.getZjgcFee()));
+                }
+            }else{
+                throw new RuntimeException(getWrongMessage(azqd));
+            }
+        }
+        return mainFee;
+    }
+
+    /**
+     * 获取安装‘无功补偿’及其子节点基础数据
+     * @param azqd  安装工程量清单计价表
+     * @param azhz  安装工程汇总表
+     * @return
+     */
+    public static JkxlDetailFee getDljjd(ImportExcel azqd, ImportExcel azhz){
+        JkxlDetailFee mainFee = getSubBaseInfos(azqd,azhz,WBS_AZ_DLJJD_HUI,NODE_AZ_DLJJD_HUI,NODE_BELONG_ZY);
+        if(mainFee!=null){
+            List<JkxlDetailFee> subFees = mainFee.getNodes();
+            if(subFees!=null&&subFees.size()>0){
+                for(int i=0;i<subFees.size();i++){
+                    JkxlDetailFee fee = subFees.get(i);
+                    if(fee.getWbsCode().equals("23161000")){
+                        getSubBaseInfos(azqd,fee,"全站电缆",WBS_AZ_QZDL,NODE_AZ_QZDL,NODE_BELONG_ZY);
+                    }
+                }
+            }
+        }
+        return mainFee;
+    }
+    /**
+     * 获取安装‘辅助生产工程’及其子节点基础数据
+     * @param jzqd  建筑工程量清单计价表
+     * @param jzhz  建筑工程汇总表
+     * @return
+     */
+    public static JkxlDetailFee getFzscgc(ImportExcel jzqd, ImportExcel jzhz){
+        JkxlDetailFee mainFee = getBaseInfo(jzqd,jzhz,WBS_AZ_FZSCGC_HUI[0],NODE_AZ_FZSCGC_HUI[0]);
+        if(mainFee!=null){
+            String[] subWbs = Arrays.copyOfRange(WBS_AZ_FZSCGC_HUI,1,WBS_AZ_FZSCGC_HUI.length);
+            String[] subNodes = Arrays.copyOfRange(NODE_AZ_FZSCGC_HUI,1,NODE_AZ_FZSCGC_HUI.length);
+            List<JkxlDetailFee> nodes = getBaseInfos(jzqd,jzhz,subWbs,subNodes);
+            mainFee.setNodes(nodes);
+        }
+        return mainFee;
+    }
+
+
+
+    /**
+     * ’配电装置建筑-构架及设备基础‘专用的数据处理方法
+     * @param list 构架及设备基础子节点列表
+     * @return
+     */
+    private static List<JkxlDetailFee> gjjsbjcDeal(List<JkxlDetailFee> list){
+        Map<String,JkxlDetailFee> map = new HashMap<>();
+        if(list==null||list.size()==0){
+            return null;
+        }
+        for(int i = 0;i<list.size();i++){
+            JkxlDetailFee fee = list.get(i);
+            String wbs = fee.getWbsCode();
+            String supWbs = wbs.substring(0,5)+"000";
+            JkxlDetailFee supFee = map.get(supWbs);
+            if(supFee==null){
+                supFee = new JkxlDetailFee(supWbs);
+                map.put(supWbs,supFee);
+            }
+            supFee.setOriginalTotalCost(DoubleUtil.add(supFee.getOriginalTotalCost(),fee.getOriginalTotalCost()));
+            supFee.setZjgcFee(DoubleUtil.add(supFee.getZjgcFee(),fee.getZjgcFee()));
+            supFee.setOriginalRgCost(DoubleUtil.add(supFee.getOriginalRgCost(),fee.getOriginalRgCost()));
+            supFee.setOriginalCbrCost(DoubleUtil.add(supFee.getOriginalCbrCost(),fee.getOriginalCbrCost()));
+            supFee.setOriginalFbrCost(DoubleUtil.add(supFee.getOriginalFbrCost(),fee.getOriginalFbrCost()));
+            supFee.setOriginalJxCost(DoubleUtil.add(supFee.getOriginalJxCost(),fee.getOriginalJxCost()));
+            List<JkxlDetailFee> subNodes = supFee.getNodes();
+            if(subNodes==null){
+                subNodes = new ArrayList<>();
+                supFee.setNodes(subNodes);
+            }
+            subNodes.add(fee);
+        }
+        List<JkxlDetailFee> fees = new ArrayList<>();
+        for(JkxlDetailFee fee:map.values()){
+            fees.add(fee);
+        }
+        return fees;
+    }
+
+    /**
+     * 根据角标返回子节点名称列表
+     * @param excel
+     * @param mark  角标
+     * @param column 在页签第column列查找子节点
+     * @param type 子节点归属,1:主要生产工程 2:辅助生产工程 3:与站址有关的单项工程
+     * @return
+     */
+    public static List<String> getSubNodes(ImportExcel excel,String mark,int column,int type){
+
+        int startRow = 0;
+        int lastRow = excel.getLastDataRowNum();
+        if(type==NODE_BELONG_ZY) {
+            for (int i = 0; i < lastRow; i++) {
+                String name = excel.getValue(i + 1, column);
+                if (name.contains("辅助生产工程")) {
+                    lastRow = i + 1;
+                    break;
+                }
+            }
+            if(lastRow == excel.getLastDataRowNum()){
+                for (int i = 0; i < lastRow; i++) {
+                    String name = excel.getValue(i + 1, column);
+                    if (name.contains("与站址有关的单项工程")) {
+                        lastRow = i + 1;
+                        break;
+                    }
+                }
+            }
+        }
+        if(type==NODE_BELONG_FZ){
+            for (int i = 0; i < lastRow; i++) {
+                String name = excel.getValue(i + 1, column);
+                if (name.contains("辅助生产工程")) {
+                    startRow = i + 1;
+                    break;
+                }
+            }
+            for (int i = 0; i < lastRow; i++) {
+                String name = excel.getValue(i + 1, column);
+                if (name.contains("与站址有关的单项工程")) {
+                    lastRow = i + 1;
+                    break;
+                }
+            }
+        }
+        if(type==NODE_BELONG_DX){
+            for (int i = 0; i < lastRow; i++) {
+                String name = excel.getValue(i + 1, column);
+                if (name.contains("与站址有关的单项工程")) {
+                    startRow = i + 1;
+                    break;
+                }
+            }
+        }
+
+        List<String> subNodes = new ArrayList<>();
+        for(int i=startRow;i<lastRow;i++){
+            String name = excel.getValue(i+1,column);
+            String subNodeMark = getMark(name);
+//            判断角标存在、以父角标开头、在父角标后紧跟一个.且这个.是最后一个、最后一个.后面还有数字
+            if(subNodeMark!=null&&subNodeMark.startsWith(mark)&&subNodeMark.lastIndexOf(".")==mark.length()&&subNodeMark.length()>(mark.length()+1)){
+                subNodes.add(name);
+            }
+        }
+        return subNodes;
+    }
+
+    /**
+     * 获取角标,此角标为在字符串开头的正则为//d|//.的子字符串
+     * @param node
+     * @return
+     */
+    public static String getMark(String node){
+        if(node != null){
+            Pattern pattern = Pattern.compile(MARK_EXP);
+            Matcher matcher = pattern.matcher(node);
+            if(matcher.find()){
+                String mark = matcher.group();
+                if(node.trim().startsWith(mark)){
+                    return mark;
+                }
+            }
+        }
+        return null;
+
+    }
+
+    /**
+     * 获取节点角标,若数据不符合规范,找不到角标则返回null
+     *
+     * @param excel    结算书
+     * @param nodeName 查找节点名称
+     * @param column   查找列
+     * @return
+     */
+    public static String getNodeMark(ImportExcel excel,String nodeName,int column){
+        int lastRow = excel.getLastDataRowNum();
+        String mark = null;
+        for(int i=0;i<lastRow;i++){
+            String name = excel.getValue(i+1,column);
+            if(name.equals("")){
+                continue;
+            }
+            if(name.contains(nodeName)){
+                Pattern pattern = Pattern.compile(MARK_EXP);
+                Matcher matcher = pattern.matcher(name);
+                if(matcher.find()){
+                    String str = matcher.group();
+                    if(name.trim().startsWith(str)){
+                        mark = str;
+                    }
+                }
+                break;
+            }
+        }
+        return mark;
+    }
+
+    /**
+     * 生成错误信息
+     * @param excel 结算书页签
+     * @return
+     */
+    public static String getWrongMessage(ImportExcel excel){
+        if(excel != null){
+            return "《"+ImportExcel.getSheet(excel).getSheetName()+"》数据不规范!";
+        }else{
+            return "变电站数据处理错误!";
+        }
+    }
+
+}