CodeLife Leno 5 месяцев назад
Родитель
Сommit
987d578e3a
32 измененных файлов с 1522 добавлено и 34 удалено
  1. BIN
      Procedure/backend/project/lib/apfloat-1.10.1.jar
  2. BIN
      Procedure/backend/project/lib/disruptor-4.0.0.jar
  3. BIN
      Procedure/backend/project/lib/jgrapht-core-1.5.2.jar
  4. BIN
      Procedure/backend/project/lib/jheaps-0.14.jar
  5. 31 0
      Procedure/backend/project/qodana.yaml
  6. 84 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/CalcRunning.java
  7. 27 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcForkJoinWorkerThread.java
  8. 87 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcRecursiveTask.java
  9. 82 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcTaskResult.java
  10. 36 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcUnitThreadFactory.java
  11. 22 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/fianl/CalcTaskResultType.java
  12. 56 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/CalcException.java
  13. 19 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/CalcResult.java
  14. 265 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/CalcUnit.java
  15. 7 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/finals/CalcStatus.java
  16. 24 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/finals/CalcType.java
  17. 124 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/CalcTaskService.java
  18. 53 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/CalcTaskUnit.java
  19. 52 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/DataQualityUnit.java
  20. 52 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/GeneralLedgerUnit.java
  21. 52 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/IntegratedRWAUnit.java
  22. 52 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/ProjectDivisionUnit.java
  23. 52 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/QualifiedSlowReleaseUnit.java
  24. 52 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/RiskExposureUnit.java
  25. 52 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/SingleRWAUnit.java
  26. 54 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/StageUnit.java
  27. 39 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/interfaces/Calc.java
  28. 8 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/interfaces/CalcTaskRunningService.java
  29. 105 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/utils/DateChecker.java
  30. 31 31
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/parameter/utils/FilesValueCheckUtils.java
  31. 1 0
      Procedure/backend/project/src/main/java/com/sundata/product/rwa/rwacalcconfig004rwa/service/MeteringManageService.java
  32. 3 3
      Procedure/backend/project/src/main/resources/application.yml

BIN
Procedure/backend/project/lib/apfloat-1.10.1.jar


BIN
Procedure/backend/project/lib/disruptor-4.0.0.jar


BIN
Procedure/backend/project/lib/jgrapht-core-1.5.2.jar


BIN
Procedure/backend/project/lib/jheaps-0.14.jar


+ 31 - 0
Procedure/backend/project/qodana.yaml

@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------#
+#               Qodana analysis is configured by qodana.yaml file               #
+#             https://www.jetbrains.com/help/qodana/qodana-yaml.html            #
+#-------------------------------------------------------------------------------#
+version: "1.0"
+
+#Specify inspection profile for code analysis
+profile:
+  name: qodana.starter
+
+#Enable inspections
+#include:
+#  - name: <SomeEnabledInspectionId>
+
+#Disable inspections
+#exclude:
+#  - name: <SomeDisabledInspectionId>
+#    paths:
+#      - <path/where/not/run/inspection>
+
+projectJDK: "17" #(Applied in CI/CD pipeline)
+
+#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
+#bootstrap: sh ./prepare-qodana.sh
+
+#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
+#plugins:
+#  - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
+
+#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
+linter: jetbrains/qodana-jvm:2024.3

+ 84 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/CalcRunning.java

@@ -0,0 +1,84 @@
+package com.sundata.product.rwa.calc.running;
+
+import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.StrUtil;
+
+import com.sundata.product.rwa.calc.running.threads.CalcRecursiveTask;
+import com.sundata.product.rwa.calc.running.threads.CalcTaskResult;
+import com.sundata.product.rwa.calc.running.threads.CalcUnitThreadFactory;
+import com.sundata.product.rwa.calc.running.threads.fianl.CalcTaskResultType;
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import org.jgrapht.Graph;
+import org.jgrapht.graph.DefaultDirectedGraph;
+import org.jgrapht.graph.DefaultEdge;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.ForkJoinPool;
+
+public class CalcRunning {
+    private static final Logger log = LoggerFactory.getLogger(CalcRunning.class);
+
+    private static final ConcurrentSkipListSet<String> runningList = new ConcurrentSkipListSet<>();
+
+    public CalcTaskResult startCalc(String calculateInstanceNumber, CalcUnit calcUnit, Map<String, Object> context) {
+
+        if (StrUtil.isEmpty(calculateInstanceNumber)) {
+            calculateInstanceNumber = UUID.randomUUID(Boolean.TRUE).toString(Boolean.TRUE);
+        }
+        Map<String, Object> resultMap = new HashMap<>();
+        resultMap.put("calculateInstanceNumber",calculateInstanceNumber);
+        CalcTaskResult result = new CalcTaskResult(CalcTaskResultType.SUCCESS, "200", "计算成功!", resultMap);
+
+        if (runningList.contains(calculateInstanceNumber)) {
+            log.warn("正在进行计算,请不要重复计算");
+            result.setResultType(CalcTaskResultType.Ignore);
+            result.setResult("正在进行计算,请不要重复计算");
+            return result;
+        }
+        runningList.add(calculateInstanceNumber);
+        // 创建自定义线程工厂
+        CalcUnitThreadFactory factory = new CalcUnitThreadFactory(calculateInstanceNumber);
+
+        // 创建 ForkJoinPool 并使用自定义线程工厂
+        ForkJoinPool customPool = new ForkJoinPool(4, factory, null, false);
+        final ConcurrentHashMap<String, Object> content = new ConcurrentHashMap<>(context);
+        final ConcurrentHashMap<CalcUnit, CalcResult<String, Object>> results = new ConcurrentHashMap<>();
+        final ConcurrentHashMap<CalcUnit, CalcResult<String, Object>> childResults = new ConcurrentHashMap<>();
+        final Graph<CalcUnit, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);
+
+        graph.addVertex(calcUnit);
+        graphAddVertex(graph,calcUnit,calcUnit.getSourceCalcUnits());
+        // 提交任务到自定义线程池
+        CalcRecursiveTask task = new CalcRecursiveTask(calculateInstanceNumber, calcUnit, content, graph, results,childResults);
+        CalcResult<String ,Object> resultMain = customPool.submit(task).join();
+        customPool.shutdown();
+        // 删除正在运行的处理过程
+        resultMap.putAll(resultMain);
+        runningList.remove(calculateInstanceNumber);
+        return result;
+    }
+
+    /**
+     * 递归获取并构建图形结构
+     * @param graph 图对象
+     * @param calcUnit 被计算的单元
+     * @param calcUnits 源头计算单元
+     */
+    private void graphAddVertex(Graph<CalcUnit, DefaultEdge> graph, CalcUnit calcUnit, List<CalcUnit> calcUnits) {
+        if (calcUnits != null && !calcUnits.isEmpty()) {
+            calcUnits.forEach(c -> {
+                graph.addVertex(c);
+                graph.addEdge(c, calcUnit);
+                graphAddVertex(graph,c,c.getSourceCalcUnits());
+            });
+        }
+    }
+
+}

+ 27 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcForkJoinWorkerThread.java

@@ -0,0 +1,27 @@
+package com.sundata.product.rwa.calc.running.threads;
+
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinWorkerThread;
+
+public class CalcForkJoinWorkerThread extends ForkJoinWorkerThread {
+
+    private final String calculateInstanceNumber;
+
+    /**
+     * Creates a ForkJoinWorkerThread operating in the given pool.
+     *
+     * @param pool the pool this thread works in
+     * @throws NullPointerException if pool is null
+     */
+    protected CalcForkJoinWorkerThread(ForkJoinPool pool, String calculateInstanceNumber) {
+        super(pool);
+        this.calculateInstanceNumber = calculateInstanceNumber;
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        // 设置线程名称
+        setName("计算[" + calculateInstanceNumber + "]"+"-"+getName());
+    }
+}

+ 87 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcRecursiveTask.java

@@ -0,0 +1,87 @@
+package com.sundata.product.rwa.calc.running.threads;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.date.TimeInterval;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import org.jgrapht.Graph;
+import org.jgrapht.graph.DefaultEdge;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.RecursiveTask;
+
+/**
+ * 分解用的任务类,结果有 ClacResult 组成
+ */
+public class CalcRecursiveTask extends RecursiveTask<CalcResult<String, Object>> {
+
+    private static final Logger log = LoggerFactory.getLogger(CalcRecursiveTask.class);
+
+    private final String calculateInstanceNumber;
+    private final CalcUnit calcUnit;
+    private final ConcurrentHashMap<String, Object> content;
+    private final Graph<CalcUnit, DefaultEdge> graph;
+    private final ConcurrentHashMap<CalcUnit, CalcResult<String, Object>> results;
+    private ConcurrentHashMap<CalcUnit, CalcResult<String, Object>> childResults;
+
+    public CalcRecursiveTask(String calculateInstanceNumber, CalcUnit calcUnit, ConcurrentHashMap<String, Object> content, Graph<CalcUnit, DefaultEdge> graph, ConcurrentHashMap<CalcUnit, CalcResult<String, Object>> results, ConcurrentHashMap<CalcUnit, CalcResult<String, Object>> childResults) {
+        this.calculateInstanceNumber = calculateInstanceNumber;
+        this.calcUnit = calcUnit;
+        this.content = content;
+        this.graph = graph;
+        this.results = results;
+        this.childResults = childResults;
+    }
+
+    /**
+     * The main computation performed by this task.
+     *
+     * @return the result of the computation
+     */
+    @Override
+    protected CalcResult<String, Object> compute() {
+        TimeInterval interval = new TimeInterval();
+        interval.start();
+        log.info("计算任务开始[计算流水号:{},计算单元:{}-{}-{}]",calculateInstanceNumber, calcUnit.getCalcType(),calcUnit.getCalcCode(), calcUnit.getCalcName());
+        if (results.containsKey(calcUnit)) {
+            log.info("已经计算过,不再计算[计算流水号:{},计算单元:{}-{}-{}]",calculateInstanceNumber, calcUnit.getCalcType(),calcUnit.getCalcCode(), calcUnit.getCalcName());
+            return results.get(calcUnit);
+        }
+        List<CalcUnit> predecessors = graph.incomingEdgesOf(calcUnit)
+                .stream()
+                .map(graph::getEdgeSource)
+                .toList();
+        // 如果有来源节点,则去计算来源节点并合并计算内容,如果没有来源节点,则处理
+        if (!predecessors.isEmpty()) {
+            log.debug("存在子节点,处理子节点");
+            childResults = new ConcurrentHashMap<>();
+            List<CalcRecursiveTask> tasks = predecessors.stream()
+                    .map(predecessor -> new CalcRecursiveTask(calculateInstanceNumber, predecessor, content, graph, results, childResults))
+                    .toList();
+            for (int i = 0; i < predecessors.size(); i++) {
+                CalcRecursiveTask task = tasks.get(i);
+//                task.fork();
+                childResults.put(predecessors.get(i), task.invoke());
+            }
+        }
+        ;// 假设节点名称是一个整数
+        CalcResult<String, Object> result = calcUnit.getResultContextFuture(calculateInstanceNumber, content, childResults);
+        results.put(calcUnit, result);
+        log.info("计算完成,耗时:[{}][计算流水号:{},计算单元:{}-{}-{}]", DateUtil.formatBetween(interval.interval()),calculateInstanceNumber, calcUnit.getCalcType(),calcUnit.getCalcCode(), calcUnit.getCalcName());
+        return result;
+    }
+
+
+    public Map<String, Object> getContent() {
+        return content;
+    }
+
+    public String getCalculateInstanceNumber() {
+        return calculateInstanceNumber;
+    }
+}

+ 82 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcTaskResult.java

@@ -0,0 +1,82 @@
+package com.sundata.product.rwa.calc.running.threads;
+
+
+import com.sundata.product.rwa.calc.running.threads.fianl.CalcTaskResultType;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+public class CalcTaskResult {
+
+    private CalcTaskResultType resultType;
+    private String code;
+    private String result;
+    private Map<String ,Object> resultMap;
+
+    public CalcTaskResult(CalcTaskResultType resultType, String code, String result, Map<String, Object> resultMap) {
+        this.resultType = resultType;
+        this.code = code;
+        this.result = result;
+        this.resultMap = resultMap;
+    }
+
+    public CalcTaskResultType getResultType() {
+        return resultType;
+    }
+
+    public void setResultType(CalcTaskResultType resultType) {
+        this.resultType = resultType;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        this.result = result;
+    }
+
+    public Map<String, Object> getResultMap() {
+        return resultMap;
+    }
+
+    public void setResultMap(Map<String, Object> resultMap) {
+        this.resultMap = resultMap;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", CalcTaskResult.class.getSimpleName() + "[", "]")
+                .add("resultType=" + resultType)
+                .add("code='" + code + "'")
+                .add("result='" + result + "'")
+                .add("resultMap=" + resultMap)
+                .toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || getClass() != o.getClass()) return false;
+
+        CalcTaskResult that = (CalcTaskResult) o;
+        return getResultType() == that.getResultType() && Objects.equals(getCode(), that.getCode()) && Objects.equals(getResult(), that.getResult()) && Objects.equals(getResultMap(), that.getResultMap());
+    }
+
+    @Override
+    public int hashCode() {
+        int result1 = Objects.hashCode(getResultType());
+        result1 = 31 * result1 + Objects.hashCode(getCode());
+        result1 = 31 * result1 + Objects.hashCode(getResult());
+        result1 = 31 * result1 + Objects.hashCode(getResultMap());
+        return result1;
+    }
+}

+ 36 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/CalcUnitThreadFactory.java

@@ -0,0 +1,36 @@
+package com.sundata.product.rwa.calc.running.threads;
+
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class CalcUnitThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory {
+    private static AtomicInteger counter = new AtomicInteger();
+
+
+    private final String calculateInstanceNumber;
+
+    public CalcUnitThreadFactory(String calculateInstanceNumber) {
+        this.calculateInstanceNumber = calculateInstanceNumber;
+    }
+
+    /**
+     * Returns a new worker thread operating in the given pool.
+     * Returning null or throwing an exception may result in tasks
+     * never being executed.  If this method throws an exception,
+     * it is relayed to the caller of the method (for example
+     * {@code execute}) causing attempted thread creation. If this
+     * method returns null or throws an exception, it is not
+     * retried until the next attempted creation (for example
+     * another call to {@code execute}).
+     *
+     * @param pool the pool this thread works in
+     * @return the new worker thread, or {@code null} if the request
+     * to create a thread is rejected
+     * @throws NullPointerException if the pool is null
+     */
+    @Override
+    public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+        return new CalcForkJoinWorkerThread(pool, calculateInstanceNumber);
+    }
+}

+ 22 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/running/threads/fianl/CalcTaskResultType.java

@@ -0,0 +1,22 @@
+package com.sundata.product.rwa.calc.running.threads.fianl;
+
+public enum CalcTaskResultType {
+
+    SUCCESS("成功"),OtherFailures("其他失败"),ProceduralIssues("程序问题"),ParameterProblem("参数问题"),PerformanceIssues("性能问题")
+    ,Ignore("忽略")
+    ;
+
+    private final String value;
+    CalcTaskResultType(String value){
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return value;
+    }
+}

+ 56 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/CalcException.java

@@ -0,0 +1,56 @@
+package com.sundata.product.rwa.calc.service;
+/**
+ * 自定义异常类,用于表示计算过程中发生的异常。
+ * 继承自 RuntimeException,因此是一个非受检异常。
+ */
+public class CalcException extends RuntimeException {
+
+    /**
+     * 计算实例的编号,用于标识发生异常的具体计算实例。
+     */
+    private String calculateInstanceNumber;
+
+    /**
+     * 构造函数,创建一个新的 CalcException 实例。
+     *
+     * @param calculateInstanceNumber 计算实例的编号
+     */
+    public CalcException(String calculateInstanceNumber) {
+        // 调用父类的无参构造函数
+        super();
+        // 设置计算实例的编号
+        this.calculateInstanceNumber = calculateInstanceNumber;
+    }
+
+    /**
+     * 构造函数,创建一个新的 CalcException 实例,并指定异常消息。
+     *
+     * @param calculateInstanceNumber 计算实例的编号
+     * @param message 异常消息
+     */
+    public CalcException(String calculateInstanceNumber, String message) {
+        // 调用父类的构造函数,并传入异常消息
+        super(message);
+        // 设置计算实例的编号
+        this.calculateInstanceNumber = calculateInstanceNumber;
+    }
+
+    /**
+     * 获取计算实例的编号。
+     *
+     * @return 计算实例的编号
+     */
+    public String getCalculateInstanceNumber() {
+        return calculateInstanceNumber;
+    }
+
+    /**
+     * 设置计算实例的编号。
+     *
+     * @param calculateInstanceNumber 计算实例的编号
+     */
+    public void setCalculateInstanceNumber(String calculateInstanceNumber) {
+        this.calculateInstanceNumber = calculateInstanceNumber;
+    }
+}
+

+ 19 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/CalcResult.java

@@ -0,0 +1,19 @@
+package com.sundata.product.rwa.calc.service;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class CalcResult<K, V> extends ConcurrentHashMap<K, V> {
+
+    /**
+     * 计算流水号
+     */
+    private final String calculateInstanceNumber;
+
+    public CalcResult(String calculateInstanceNumber) {
+        this.calculateInstanceNumber = calculateInstanceNumber;
+    }
+
+    public String getCalculateInstanceNumber() {
+        return calculateInstanceNumber;
+    }
+}

+ 265 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/CalcUnit.java

@@ -0,0 +1,265 @@
+package com.sundata.product.rwa.calc.service;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.date.TimeInterval;
+
+import com.sundata.product.rwa.calc.service.finals.CalcStatus;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+import com.sundata.product.rwa.calc.service.interfaces.Calc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+public abstract class CalcUnit implements Calc, Serializable {
+    private static final Logger log = LoggerFactory.getLogger(CalcUnit.class);
+    @Serial
+    private static final long serialVersionUID = 1L;
+    /**
+     * 计算单元编号
+     */
+    private final String calcCode;
+    /**
+     * 计算单元名称
+     */
+    private final String calcName;
+    /**
+     * 计算单元类型
+     */
+    private final CalcType calcType;
+
+    /**
+     * 计算状态
+     */
+    private CalcStatus status = CalcStatus.READY;
+    /**
+     * 初始化用属性对象节点
+     */
+    private final Map<String, Object> initContext;
+
+    private CompletableFuture<CalcResult<String, Object>> resultContextFuture;
+
+    /**
+     * 计算结果对象
+     */
+    private CalcResult<String, Object> resultContext;
+
+    /**
+     * 计算流水号
+     */
+    private String calculateInstanceNumber = "";
+
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public CalcUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        this.calcCode = calcCode;
+        this.calcName = calcName;
+        this.calcType = calcType;
+        this.initContext = initContext;
+    }
+
+    /**
+     * 获取计算结果的异步方法。
+     * 如果结果上下文的Future已经存在,则直接获取结果;否则,创建一个新的Future并启动计算。
+     *
+     * @param calculateInstanceNumber 计算实例的编号
+     * @param context                 计算上下文
+     * @param sourceResults           源计算结果
+     * @return 计算结果的Future
+     * @throws CalcException 如果计算过程中出现问题
+     */
+    public CalcResult<String, Object> getResultContextFuture(String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+        try {
+            // 如果结果上下文的Future已经存在,则直接获取结果
+            if (this.resultContextFuture != null) {
+                return this.resultContextFuture.get();
+            } else {
+                // 同步块,确保只有一个线程创建Future
+                synchronized (this) {
+                    // 再次检查Future是否已经被其他线程创建
+                    if (this.resultContextFuture == null) {
+                        // 创建一个新的Future并启动计算
+                        this.resultContextFuture = CompletableFuture.supplyAsync(() -> {
+                                    // 启动计算
+                                    this.startCalc(calculateInstanceNumber, context, sourceResults);
+                                    // 返回计算结果
+                                    return this.resultContext;
+                                }
+                        );
+                    }
+                    // 获取计算结果
+                    return this.resultContextFuture.get();
+                }
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            // 记录错误日志
+            log.error(e.getMessage(), e);
+            // 抛出自定义异常
+            throw new CalcException(calculateInstanceNumber, "计算出现问题,线程级别,请检查处理过程。");
+        }
+    }
+    /**
+     * 开始计算的方法。
+     *
+     * @param calculateInstanceNumber 计算实例的编号
+     * @param context 计算上下文
+     * @param sourceResults 源计算结果
+     */
+    public void startCalc(String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+        // 设置计算状态为运行中
+        setStatus(CalcStatus.RUNNING);
+        // 如果已经计算过,则不再执行计算处理,仅需要通过 initResultContext 初始化 resultContext 对象
+        if (isCalcFinished(calculateInstanceNumber)) {
+            log.info("当前计算节点为:[{}-{}-{}],曾经完成过计算,加载原始计算内容并结束", this.getCalcType(), this.getCalcCode(), this.getCalcName());
+            initResultContext(calculateInstanceNumber);
+            setStatus(CalcStatus.FINISHED);
+            return;
+        }
+        // 创建一个时间间隔对象,用于计算耗时
+        TimeInterval interval = new TimeInterval();
+        // 设置计算实例的编号
+        setCalculateInstanceNumber(calculateInstanceNumber);
+//        String calcUnitInstanceNumber = getCalcUnitInstanceNumber();
+        log.info("当前计算节点为:[{}-{}-{}],计算流水号为:{}", this.getCalcType(), this.getCalcCode(), this.getCalcName(), calculateInstanceNumber);
+        // 开始计时
+        interval.start();
+        try {
+            // 在计算之前执行的操作
+            this.beforeCalc(context);
+            // 创建一个新的计算结果对象
+            final CalcResult<String, Object> thisResult = new CalcResult<>(calculateInstanceNumber);
+            // 执行计算操作
+            this.calc(thisResult, calculateInstanceNumber, context, sourceResults);
+//            log.info("计算节点【{}-{}】完成,结果为【{}】",this.getCalcType(),this.getCalcCode(), thisResult);
+            // 如果计算结果为空,则抛出异常
+            if (thisResult.isEmpty()) {
+                throw new CalcException(calculateInstanceNumber, "请注意,计算过程中必须将 thisResult 结果数据赋值,否则父节点无法正常计算,计算错误的节点为【" + this.toString() + "】");
+            }
+            // 设置计算结果
+            setResultContext(thisResult);
+            // 在计算之后执行的操作
+            this.afterCalc(context);
+        } catch (CalcException e) {
+            // 如果计算失败,则恢复计算逻辑
+            this.calculateInstanceNumber = null;
+            log.error("计算失败,恢复计算逻辑: {}", calculateInstanceNumber, e);
+            // 设置计算状态为错误
+            setStatus(CalcStatus.ERROR);
+        }
+        // 设置计算状态为完成
+        setStatus(CalcStatus.FINISHED);
+        log.info("计算节点[{}-{}-{}]计算过程完成,耗时:{}", this.getCalcType(), this.getCalcCode(), this.getCalcName(), DateUtil.formatBetween(interval.interval()));
+    }
+    /**
+     * 判断是否已经计算过数据了
+     *
+     * @param calculateInstanceNumber 计算流水号
+     * @return 是否计算过 true 计算过 false 没有计算过
+     */
+    public abstract boolean isCalcFinished(String calculateInstanceNumber);
+
+    /**
+     * 初始化计算结果的方法,如果已经计算过,在实现过程中,应当在此方法中根据计算流水号重新初始化 resultContext 结果对象,为其他依赖对象做准备
+     * 若明明计算过本单元但再次计算时没有初始化该对象,则计算依赖出现问题无法定位与处理
+     *
+     * @param calculateInstanceNumber 计算流水号
+     */
+    public abstract void initResultContext(String calculateInstanceNumber);
+
+    /**
+     * 根据节点配置获取源节点;
+     *
+     * @return 所有源头节点
+     */
+    public abstract List<CalcUnit> getSourceCalcUnits();
+
+    public String getCalcName() {
+        return calcName;
+    }
+
+    public CalcType getCalcType() {
+        return calcType;
+    }
+
+    public Map<String, Object> getInitContext() {
+        return initContext;
+    }
+
+    public CalcResult<String, Object> getResultContext() {
+        return resultContext;
+    }
+
+    public void setResultContext(CalcResult<String, Object> resultContext) {
+        this.resultContext = resultContext;
+    }
+
+    /**
+     * 获取计算单元的流水号
+     *
+     * @return 计算单元流水号 通常由 计算流水号 + 计算单元类型 + 计算单元名称组成
+     */
+    public String getCalcUnitInstanceNumber() {
+        return calculateInstanceNumber + "-" + calcType + "-" + calcName;
+    }
+
+    /**
+     * 设置计算流水号
+     *
+     * @param calcInstanceNumber 计算流水号
+     */
+    private void setCalculateInstanceNumber(String calcInstanceNumber) {
+        this.calculateInstanceNumber = calcInstanceNumber;
+    }
+
+    public String getCalcCode() {
+        return calcCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || getClass() != o.getClass()) return false;
+
+        CalcUnit unit = (CalcUnit) o;
+        return Objects.equals(getCalcCode(), unit.getCalcCode()) && getCalcType() == unit.getCalcType() && Objects.equals(calculateInstanceNumber, unit.calculateInstanceNumber);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hashCode(getCalcCode());
+        result = 31 * result + Objects.hashCode(getCalcType());
+        result = 31 * result + Objects.hashCode(calculateInstanceNumber);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", CalcUnit.class.getSimpleName() + "[", "]")
+                .add("calculateInstanceNumber='" + calculateInstanceNumber + "'")
+                .add("calcCode='" + calcCode + "'")
+                .add("calcName='" + calcName + "'")
+                .add("calcType=" + calcType)
+                .add("resultContext=" + resultContext)
+                .toString();
+    }
+
+    public CalcStatus getStatus() {
+        return status;
+    }
+
+    private void setStatus(CalcStatus status) {
+        this.status = status;
+    }
+}

+ 7 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/finals/CalcStatus.java

@@ -0,0 +1,7 @@
+package com.sundata.product.rwa.calc.service.finals;
+
+public enum CalcStatus {
+    READY,RUNNING,FINISHED,ERROR
+    ;
+//    abstract void change();
+}

+ 24 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/finals/CalcType.java

@@ -0,0 +1,24 @@
+package com.sundata.product.rwa.calc.service.finals;
+
+public enum CalcType {
+
+    MAIN("计算任务"),STAGE("阶段"),DataQuality("数据质量"),GeneralLedger("总账勾稽"),ProjectDivision("项目划分")
+    ,RiskExposure("风险暴露分类"),QualifiedSlowRelease("合格缓释认定"),SingleRWA("单笔债项RWA"),IntegratedRWA("法人RWA")
+    ;
+
+    private final String name ;
+    private String id;
+
+    CalcType(String name){
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+}

+ 124 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/CalcTaskService.java

@@ -0,0 +1,124 @@
+package com.sundata.product.rwa.calc.service.implement;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.ReUtil;
+import cn.hutool.core.util.StrUtil;
+import com.sundata.admin.nounmanage.service.NounManageService;
+import com.sundata.product.rwa.calc.utils.DateChecker;
+import com.sundata.product.rwa.rwacalcconfig004rwa.model.MeteringManageModel;
+import com.sundata.product.rwa.rwacalcconfig004rwa.service.MeteringManageService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class CalcTaskService {
+
+    static final Logger log = LoggerFactory.getLogger(CalcTaskService.class);
+    /**
+     * 计量任务数据
+     */
+    private final MeteringManageService meteringManageService;
+    private final NounManageService nounManageService;
+
+    public CalcTaskService(MeteringManageService meteringManageService, NounManageService nounManageService) {
+        this.meteringManageService = meteringManageService;
+        this.nounManageService = nounManageService;
+    }
+
+    public MeteringManageService getMeteringManageService() {
+        return meteringManageService;
+    }
+
+    public NounManageService getNounManageService() {
+        return nounManageService;
+    }
+
+    /**
+     * 获取全部计算任务的配置
+     *
+     * @return 计算任务的配置清单(目前就一个)
+     */
+    public List<MeteringManageModel> getAllMeteringManageModel() {
+        return meteringManageService.getDataList(new MeteringManageModel());
+    }
+
+    /**
+     * 通过传入的日期字符串判断对应的日期需要跑哪些计算任务
+     *
+     * @param dateStr 日期字符串
+     * @return 满足条件的计算任务
+     */
+    public List<MeteringManageModel> takeShouldRunMetering(String dateStr) {
+        if (StrUtil.isBlank(dateStr)) {
+            throw new IllegalArgumentException("日期字符串为空");
+        }
+        if (dateStr.length() != 10 || !ReUtil.contains("^\\d{4}-[0,1]{1}\\d{1}-[0,1,2,3]{1}\\d{1}", dateStr)) {
+            throw new IllegalArgumentException("日期字符串不满足格式");
+        }
+        List<MeteringManageModel> meteringManageModels = getAllMeteringManageModel();
+//        List<DictTree> frequencies = nounManageService.getNounTree("FREQUENCY");
+        List<MeteringManageModel> shouldRunMetering = new ArrayList<>();
+        Calendar calendar = Calendar.getInstance();
+
+        for (MeteringManageModel meteringManageModel : meteringManageModels) {
+            calendar.setTime(DateUtil.parse(dateStr));
+            String adjustDateString = meteringManageModel.getAdjustDate();
+            if (!NumberUtil.isNumber(adjustDateString)) {
+                adjustDateString = "0";
+            }
+            int adjustDate = Integer.parseInt(adjustDateString);
+            calendar.add(Calendar.DATE, -adjustDate);
+
+            // 如果是月初则可运算
+            if (DateChecker.isStartOfMonth(calendar) && "1".equals(meteringManageModel.getCalctaskRate())) {
+                shouldRunMetering.add(meteringManageModel);
+            }
+            if (DateChecker.isStartOfQuarter(calendar) && "2".equals(meteringManageModel.getCalctaskRate())) {
+                shouldRunMetering.add(meteringManageModel);
+            }
+            if (DateChecker.isStartOfYear(calendar) && "3".equals(meteringManageModel.getCalctaskRate())) {
+                shouldRunMetering.add(meteringManageModel);
+            }
+            if (DateChecker.isEndOfMonth(calendar) && "4".equals(meteringManageModel.getCalctaskRate())) {
+                shouldRunMetering.add(meteringManageModel);
+            }
+            if (DateChecker.isEndOfQuarter(calendar) && "5".equals(meteringManageModel.getCalctaskRate())) {
+                shouldRunMetering.add(meteringManageModel);
+            }
+            if (DateChecker.isEndOfYear(calendar) && "6".equals(meteringManageModel.getCalctaskRate())) {
+                shouldRunMetering.add(meteringManageModel);
+            }
+        }
+        return shouldRunMetering;
+    }
+
+    /**
+     * 根据提供的对象执行计算任务
+     *
+     * @param meteringManageModel 计算任务对象
+     */
+    private void executeOneMetering(MeteringManageModel meteringManageModel, String dateStr) {
+
+    }
+
+
+    /**
+     * 根据传入的数据日期筛选需要跑的计算任务并执行计算。
+     * @param dateStr 数据日期
+     */
+    public void executeMainMetering(String dateStr) {
+        log.debug("执行【{}】的计算任务", dateStr);
+        List<MeteringManageModel> meteringManageModels = takeShouldRunMetering(dateStr);
+        log.debug("执行【{}】的计算任务,分别为:【{}】",dateStr,meteringManageModels.stream().map(MeteringManageModel::getCalctaskTypeName).collect(Collectors.joining(",")));
+        for (MeteringManageModel meteringManageModel : meteringManageModels) {
+            executeOneMetering(meteringManageModel, dateStr);
+        }
+    }
+}

+ 53 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/CalcTaskUnit.java

@@ -0,0 +1,53 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class CalcTaskUnit extends CalcUnit {
+
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public CalcTaskUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 52 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/DataQualityUnit.java

@@ -0,0 +1,52 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class DataQualityUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public DataQualityUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 52 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/GeneralLedgerUnit.java

@@ -0,0 +1,52 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class GeneralLedgerUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public GeneralLedgerUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 52 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/IntegratedRWAUnit.java

@@ -0,0 +1,52 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class IntegratedRWAUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public IntegratedRWAUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 52 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/ProjectDivisionUnit.java

@@ -0,0 +1,52 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class ProjectDivisionUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public ProjectDivisionUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 52 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/QualifiedSlowReleaseUnit.java

@@ -0,0 +1,52 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class QualifiedSlowReleaseUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public QualifiedSlowReleaseUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 52 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/RiskExposureUnit.java

@@ -0,0 +1,52 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class RiskExposureUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public RiskExposureUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 52 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/SingleRWAUnit.java

@@ -0,0 +1,52 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class SingleRWAUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public SingleRWAUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 54 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/implement/units/StageUnit.java

@@ -0,0 +1,54 @@
+package com.sundata.product.rwa.calc.service.implement.units;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+import com.sundata.product.rwa.calc.service.finals.CalcType;
+
+import java.util.List;
+import java.util.Map;
+
+public class StageUnit extends CalcUnit {
+    /**
+     * 创建数据单元的绝对对象,对象必须包含如下参数
+     *
+     * @param calcCode    计算对象编号
+     * @param calcName    计算对象名称
+     * @param calcType    计算类型
+     * @param initContext 计算单元初始化参数
+     */
+    public StageUnit(String calcCode, String calcName, CalcType calcType, Map<String, Object> initContext) {
+        super(calcCode, calcName, calcType, initContext);
+    }
+
+    @Override
+    public boolean isCalcFinished(String calculateInstanceNumber) {
+        return false;
+    }
+
+    @Override
+    public void initResultContext(String calculateInstanceNumber) {
+
+    }
+
+    @Override
+    public List<CalcUnit> getSourceCalcUnits() {
+        SpringUtil.getBean("calcUnitService");
+        return List.of();
+    }
+
+    @Override
+    public void afterCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void beforeCalc(Map<String, Object> context) {
+
+    }
+
+    @Override
+    public void calc(CalcResult<String, Object> thisResult, String calculateInstanceNumber, Map<String, Object> context, Map<CalcUnit, CalcResult<String, Object>> sourceResults) {
+
+    }
+}

+ 39 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/interfaces/Calc.java

@@ -0,0 +1,39 @@
+package com.sundata.product.rwa.calc.service.interfaces;
+
+import com.sundata.product.rwa.calc.service.CalcResult;
+import com.sundata.product.rwa.calc.service.CalcUnit;
+
+import java.util.Map;
+
+public interface Calc {
+
+    /**
+     * 计算之后的方法,可实现为空
+     */
+    void afterCalc(final Map<String, Object> context);
+
+    /**
+     * 计算之前,可实现空
+     */
+    void beforeCalc(final Map<String, Object> context);
+
+    /**
+     * 必须实现的主体计算内容
+     *
+     * @param thisResult              本计算单元的结果
+     * @param sourceResults           源头计算节点的结果
+     * @param context                 节点计算参数清单
+     * @param calculateInstanceNumber 计算流水号
+     */
+    void calc(final CalcResult<String, Object> thisResult, String calculateInstanceNumber, final Map<String, Object> context, final Map<CalcUnit, CalcResult<String, Object>> sourceResults);
+
+    /**
+     * 启动计算的方法
+     *
+     * @param sourceResults           源头计算节点的结果
+     * @param context                 节点计算参数清单
+     * @param calculateInstanceNumber 计算流水号
+     * @return
+     */
+    void startCalc(String calculateInstanceNumber, final Map<String, Object> context, final Map<CalcUnit, CalcResult<String, Object>> sourceResults);
+}

+ 8 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/service/interfaces/CalcTaskRunningService.java

@@ -0,0 +1,8 @@
+package com.sundata.product.rwa.calc.service.interfaces;
+
+/**
+ * 计算任务处理过程,计算
+ */
+public interface CalcTaskRunningService {
+
+}

+ 105 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/calc/utils/DateChecker.java

@@ -0,0 +1,105 @@
+package com.sundata.product.rwa.calc.utils;
+
+import java.time.LocalDate;
+import java.time.temporal.TemporalAdjusters;
+import java.util.Calendar;
+import java.util.Date;
+
+public class DateChecker {
+
+    // 重载方法:支持 java.util.Date
+    public static boolean isStartOfYear(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return isStartOfYear(calendar);
+    }
+
+    public static boolean isEndOfYear(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return isEndOfYear(calendar);
+    }
+
+    public static boolean isStartOfQuarter(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return isStartOfQuarter(calendar);
+    }
+
+    public static boolean isEndOfQuarter(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return isEndOfQuarter(calendar);
+    }
+
+    public static boolean isStartOfMonth(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return isStartOfMonth(calendar);
+    }
+
+    public static boolean isEndOfMonth(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return isEndOfMonth(calendar);
+    }
+
+    // 重载方法:支持 java.util.Calendar
+    public static boolean isStartOfYear(Calendar calendar) {
+        return calendar.get(Calendar.MONTH) == Calendar.JANUARY && calendar.get(Calendar.DAY_OF_MONTH) == 1;
+    }
+
+    public static boolean isEndOfYear(Calendar calendar) {
+        return calendar.get(Calendar.MONTH) == Calendar.DECEMBER && calendar.get(Calendar.DAY_OF_MONTH) == 31;
+    }
+
+    public static boolean isStartOfQuarter(Calendar calendar) {
+        int month = calendar.get(Calendar.MONTH);
+        return (month == Calendar.JANUARY || month == Calendar.APRIL || month == Calendar.JULY || month == Calendar.OCTOBER)
+                && calendar.get(Calendar.DAY_OF_MONTH) == 1;
+    }
+
+    public static boolean isEndOfQuarter(Calendar calendar) {
+        int month = calendar.get(Calendar.MONTH);
+        int lastDayOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+        return (month == Calendar.MARCH || month == Calendar.JUNE || month == Calendar.SEPTEMBER || month == Calendar.DECEMBER)
+                && calendar.get(Calendar.DAY_OF_MONTH) == lastDayOfMonth;
+    }
+
+    public static boolean isStartOfMonth(Calendar calendar) {
+        return calendar.get(Calendar.DAY_OF_MONTH) == 1;
+    }
+
+    public static boolean isEndOfMonth(Calendar calendar) {
+        int lastDayOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+        return calendar.get(Calendar.DAY_OF_MONTH) == lastDayOfMonth;
+    }
+
+    // 重载方法:支持 java.time.LocalDate
+    public static boolean isStartOfYear(LocalDate date) {
+        return date.getMonthValue() == 1 && date.getDayOfMonth() == 1;
+    }
+
+    public static boolean isEndOfYear(LocalDate date) {
+        return date.getMonthValue() == 12 && date.getDayOfMonth() == 31;
+    }
+
+    public static boolean isStartOfQuarter(LocalDate date) {
+        int month = date.getMonthValue();
+        return (month == 1 || month == 4 || month == 7 || month == 10) && date.getDayOfMonth() == 1;
+    }
+
+    public static boolean isEndOfQuarter(LocalDate date) {
+        LocalDate endOfQuarter = date.with(TemporalAdjusters.lastDayOfMonth());
+        int month = endOfQuarter.getMonthValue();
+        return (month == 3 || month == 6 || month == 9 || month == 12) && date.equals(endOfQuarter);
+    }
+
+    public static boolean isStartOfMonth(LocalDate date) {
+        return date.getDayOfMonth() == 1;
+    }
+
+    public static boolean isEndOfMonth(LocalDate date) {
+        return date.equals(date.with(TemporalAdjusters.lastDayOfMonth()));
+    }
+}

+ 31 - 31
Procedure/backend/project/src/main/java/com/sundata/product/rwa/parameter/utils/FilesValueCheckUtils.java

@@ -5,10 +5,7 @@ import com.sundata.admin.excelmanage.mapper.RptDefineMapper;
 import com.sundata.admin.excelmanage.model.RptDefineModel;
 import com.sundata.common.base.BaseMapper;
 import com.sundata.common.base.BaseService;
-import com.sundata.common.util.DBExecutor;
 import com.sundata.common.util.FileUtil;
-import com.sundata.product.rwa.parameter.model.PolicyBankModel;
-import com.sundata.product.rwa.parameter.model.SovereignModel;
 import jakarta.servlet.http.HttpServletResponse;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
@@ -20,7 +17,10 @@ import org.jxls.transform.poi.JxlsPoiTemplateFillerBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashMap;
@@ -28,47 +28,43 @@ import java.util.List;
 import java.util.Map;
 
 public class FilesValueCheckUtils extends BaseService<RptDefineModel> {
-    @Autowired
-    // private RptReportInfoMapper<RptReportInfoModel> rptReportInfoMapper;
-    private RptDefineMapper<RptDefineModel> rptDefineMapper;
-    @Override
-    public BaseMapper<RptDefineModel> getMapper() {
-        return this.rptDefineMapper;
-    }
     private static final String XLSX = ".xlsx";
     private static final String XLS = ".xls";
     private static final String ENDNAME = "模板";
     // 定义jackson对象
     private static final ObjectMapper json = new ObjectMapper();
+    @Autowired
+    // private RptReportInfoMapper<RptReportInfoModel> rptReportInfoMapper;
+    private RptDefineMapper<RptDefineModel> rptDefineMapper;
 
     // 文件格式校验并初始化
-    public static Workbook workBookInstance (InputStream io, MultipartFile file) throws IOException {
+    public static Workbook workBookInstance(InputStream io, MultipartFile file) throws IOException {
         String fileName = file.getOriginalFilename().toLowerCase();
         // 导入文件流转换为poi对象
-        Workbook book=null;
+        Workbook book = null;
         if (fileName.endsWith(XLSX)) {
             book = new XSSFWorkbook(io);
         } else if (fileName.endsWith(XLS)) {
             book = new HSSFWorkbook(io);
         } else {
-           return null;
+            return null;
         }
         return book;
     }
 
     // 文件内容校验
-    public static String  castFileValue (Workbook book,Class clazz,List modelList) throws IOException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+    public static String castFileValue(Workbook book, Class clazz, List modelList) throws IOException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
         // 接收反射对象
         Object object = null;
         // 获取实体类内方法
         Method method = clazz.getMethod("getCastFileCellToJson");
         // 执行方法获得返回值
-        HashMap<String,String> map =(HashMap<String,String>) method.invoke(clazz);
+        HashMap<String, String> map = (HashMap<String, String>) method.invoke(clazz);
 
         // 读取文件sheet页
         int sheetNum = book.getNumberOfSheets();
         // 遍历每一个sheet页
-        for (int i =0;i<=sheetNum-1;i++){
+        for (int i = 0; i <= sheetNum - 1; i++) {
             // 读取第i个sheet页
             Sheet sheet = book.getSheetAt(i);
             // 当前sheet页的数据总行数
@@ -78,9 +74,9 @@ public class FilesValueCheckUtils extends BaseService<RptDefineModel> {
                 return "文件内容为空,请检查导入数据是否正确";
             }
             // 遍历当前sheet页每一行
-            for (int rowNum=0;rowNum<=dataRows;rowNum++){
+            for (int rowNum = 0; rowNum <= dataRows; rowNum++) {
                 // 每一行数据按键值对存进map
-                HashMap<String,String> jsonMap = new HashMap<String,String>();
+                HashMap<String, String> jsonMap = new HashMap<String, String>();
                 // 将反射对象进行实例化
                 object = clazz.newInstance();
 
@@ -92,7 +88,7 @@ public class FilesValueCheckUtils extends BaseService<RptDefineModel> {
                 // 获取当前行的列数
                 int cellNums = sheet.getRow(rowNum).getLastCellNum();
                 // 遍历当前行的每一列
-                for (int cellNum = 0; cellNum<=cellNums-1; cellNum++){
+                for (int cellNum = 0; cellNum <= cellNums - 1; cellNum++) {
                     Cell cellData = null;
 
                     // 列名检查
@@ -105,11 +101,11 @@ public class FilesValueCheckUtils extends BaseService<RptDefineModel> {
 
                     // 数据行超列
                     if (sheet.getRow(0).getLastCellNum() < sheet.getRow(rowNum).getLastCellNum()) {
-                        return "第"+ (rowNum+1)+"行"+ (sheet.getRow(rowNum).getLastCellNum()) + "列导入数据超过应有列数";
+                        return "第" + (rowNum + 1) + "行" + (sheet.getRow(rowNum).getLastCellNum()) + "列导入数据超过应有列数";
                     }
 
                     if (sheet.getRow(0).getLastCellNum() > sheet.getRow(rowNum).getLastCellNum()) {
-                        return "第"+ (rowNum+1)+"行"+ (sheet.getRow(rowNum).getLastCellNum()+1) + "列导入数据为空,请检查";
+                        return "第" + (rowNum + 1) + "行" + (sheet.getRow(rowNum).getLastCellNum() + 1) + "列导入数据为空,请检查";
                     }
 
                     // 获得当前列数据
@@ -118,12 +114,12 @@ public class FilesValueCheckUtils extends BaseService<RptDefineModel> {
                     // 校验导入数据(数据为空就提示)
                     if (null == sheet.getRow(rowNum).getCell(cellNum)
                             || "".equals(sheet.getRow(rowNum).getCell(cellNum).toString())) {
-                        return "第"+ (rowNum+1)+"行"+ (cellNum+1) + "列导入数据为空,请检查";
+                        return "第" + (rowNum + 1) + "行" + (cellNum + 1) + "列导入数据为空,请检查";
                     }
                     // 获取列名对应的英文
                     String key = map.get(sheet.getRow(0).getCell(cellNum).toString());
                     // 将英文名与数据存进map
-                    jsonMap.put(key,cellData.toString());
+                    jsonMap.put(key, cellData.toString());
 
                 }
                 // 第一行不计入数据
@@ -131,7 +127,7 @@ public class FilesValueCheckUtils extends BaseService<RptDefineModel> {
                     // 实例jackson对象
                     ObjectMapper json = new ObjectMapper();
                     // 将文件数据内容转化为实体类对象
-                    object = json.convertValue(jsonMap,clazz);
+                    object = json.convertValue(jsonMap, clazz);
                     // 插入list
                     modelList.add(object);
                 }
@@ -141,26 +137,30 @@ public class FilesValueCheckUtils extends BaseService<RptDefineModel> {
     }
 
     // 模板下载
-    public static void templateUploadModel(HttpServletResponse response, String fileName,String templatePath) throws IOException {
+    public static void templateUploadModel(HttpServletResponse response, String fileName, String templatePath) throws IOException {
 
         String templatePath1 = "C:/Users/86156/Desktop";
         // 向响应体内设置附件路径以及文件名
-        FileUtil.getContent(fileName+XLSX,response,templatePath1);
+        FileUtil.getContent(fileName + XLSX, response, templatePath1);
     }
 
     // 导出数据
     public static void exportExcelModel(HttpServletResponse response, List model, String templatePath, String fileName) throws FileNotFoundException {
-     //   String templatePath1 = "C:/Users/86156/Desktop/templatetest/";
+        //   String templatePath1 = "C:/Users/86156/Desktop/templatetest/";
         Map<String, Object> data = new HashMap<>();
         //sheet页的名字
         data.put("models", model);
         JxlsPoiTemplateFillerBuilder.newInstance()
-                .withTemplate(templatePath+fileName+ENDNAME+XLSX)
+                .withTemplate(templatePath + fileName + ENDNAME + XLSX)
                 .build()
-                .fill(data, new JxlsOutputFile(new File(templatePath+fileName+XLSX)));
-        FileUtil.getContent(fileName+XLSX,response,templatePath);
+                .fill(data, new JxlsOutputFile(new File(templatePath + fileName + XLSX)));
+        FileUtil.getContent(fileName + XLSX, response, templatePath);
     }
 
+    @Override
+    public BaseMapper<RptDefineModel> getMapper() {
+        return this.rptDefineMapper;
+    }
 
 
 }

+ 1 - 0
Procedure/backend/project/src/main/java/com/sundata/product/rwa/rwacalcconfig004rwa/service/MeteringManageService.java

@@ -22,6 +22,7 @@ public class MeteringManageService {
      * @throws:
      */
     public List<MeteringManageModel> getDataList(MeteringManageModel model) {
+        if (model == null) model = new MeteringManageModel();
         return meteringManageMapper.getDataList(model);
     }
 

+ 3 - 3
Procedure/backend/project/src/main/resources/application.yml

@@ -27,9 +27,9 @@ spring:
   #  username: testdb
   #  password: testdb
   datasource:
-    jdbcUrl: jdbc:mysql://192.168.51.220:3306/rwa_test
-    username: test
-    password: test
+    jdbcUrl: jdbc:mysql://localhost:3306/rwa_dev
+    username: rwa_dev
+    password: rwa_dev
 
     encrypted: false # 是否使用加密后的数据库密码
     #hikari 链接池配置