|
@@ -0,0 +1,225 @@
|
|
|
|
|
+package com.hdkj.lt.si.service.staticgrid.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
|
|
+import com.hdkj.lt.si.dao.StaticIndicatorMetricMapper;
|
|
|
|
|
+import com.hdkj.lt.si.dao.StaticIndicatorResultMapper;
|
|
|
|
|
+import com.hdkj.lt.si.dao.StaticProblemDetailMapper;
|
|
|
|
|
+import com.hdkj.lt.si.entity.staticgrid.StaticIndicatorMetric;
|
|
|
|
|
+import com.hdkj.lt.si.entity.staticgrid.StaticIndicatorResult;
|
|
|
|
|
+import com.hdkj.lt.si.entity.staticgrid.StaticProblemDetail;
|
|
|
|
|
+import com.hdkj.lt.si.service.remote.impl.AlgorithmRemoteCallServiceImpl;
|
|
|
|
|
+import com.hdkj.lt.si.service.staticgrid.StaticIndicatorResultService;
|
|
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 静态网架评估结果服务实现
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 调用算法接口获取完整 JSON,解析后写入 3 张表:
|
|
|
|
|
+ * <ol>
|
|
|
|
|
+ * <li>t_static_indicator_result — 主表(一次计算一行)</li>
|
|
|
|
|
+ * <li>t_static_indicator_metric — 指标明细(county + feeder 两级扁平化)</li>
|
|
|
|
|
+ * <li>t_static_problem_detail — 问题详情</li>
|
|
|
|
|
+ * </ol>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author lsl
|
|
|
|
|
+ * @since 2026-07-19
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+@RequiredArgsConstructor
|
|
|
|
|
+public class StaticIndicatorResultServiceImpl
|
|
|
|
|
+ extends ServiceImpl<StaticIndicatorResultMapper, StaticIndicatorResult>
|
|
|
|
|
+ implements StaticIndicatorResultService {
|
|
|
|
|
+
|
|
|
|
|
+ private final StaticIndicatorMetricMapper metricMapper;
|
|
|
|
|
+ private final StaticProblemDetailMapper problemDetailMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource(type = AlgorithmRemoteCallServiceImpl.class)
|
|
|
|
|
+ private AlgorithmRemoteCallServiceImpl algorithmRemoteCallService;
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public Long saveStaticGridResult(String batchId, Integer countyId) {
|
|
|
|
|
+ // 1. 调算法
|
|
|
|
|
+ String rawResponse = algorithmRemoteCallService.queryStaticGridIndicators();
|
|
|
|
|
+ if (StringUtils.isBlank(rawResponse)) {
|
|
|
|
|
+ log.warn("静态网架评估接口返回空 batchId={}, countyId={}", batchId, countyId);
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 解析顶层
|
|
|
|
|
+ JSONObject root = JSON.parseObject(rawResponse);
|
|
|
|
|
+ String responseType = root.getString("response_type");
|
|
|
|
|
+ String requestId = root.getString("request_id");
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject countyBasicInfo = root.getJSONObject("county_basic_info");
|
|
|
|
|
+ String countySid = countyBasicInfo != null ? countyBasicInfo.getString("county_sid") : null;
|
|
|
|
|
+ String countyName = countyBasicInfo != null ? countyBasicInfo.getString("county_name") : null;
|
|
|
|
|
+ JSONArray feederIdsArr = countyBasicInfo != null ? countyBasicInfo.getJSONArray("feeder_ids") : null;
|
|
|
|
|
+ String feederIds = feederIdsArr != null ? String.join(",", feederIdsArr.toJavaList(String.class)) : null;
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject calcResult = root.getJSONObject("calculation_result");
|
|
|
|
|
+ JSONObject countyResult = calcResult != null ? calcResult.getJSONObject("county_result") : null;
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject dataQuality = calcResult != null ? calcResult.getJSONObject("data_quality") : null;
|
|
|
|
|
+ String dataQualityStatus = dataQuality != null ? dataQuality.getString("status") : null;
|
|
|
|
|
+ BigDecimal completenessRate = dataQuality != null ? dataQuality.getBigDecimal("completeness_rate") : null;
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject processInfo = root.getJSONObject("process_info");
|
|
|
|
|
+ String algorithm = processInfo != null ? processInfo.getString("algorithm") : null;
|
|
|
|
|
+ BigDecimal durationSec = processInfo != null ? processInfo.getBigDecimal("duration_sec") : null;
|
|
|
|
|
+ String status = processInfo != null ? processInfo.getString("status") : null;
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 写主表
|
|
|
|
|
+ StaticIndicatorResult mainRecord = StaticIndicatorResult.builder()
|
|
|
|
|
+ .batchId(batchId)
|
|
|
|
|
+ .countyId(countyId)
|
|
|
|
|
+ .countySid(countySid)
|
|
|
|
|
+ .countyName(countyName)
|
|
|
|
|
+ .feederIds(feederIds)
|
|
|
|
|
+ .responseType(responseType)
|
|
|
|
|
+ .requestId(requestId)
|
|
|
|
|
+ .rawResponse(rawResponse)
|
|
|
|
|
+ .algorithm(algorithm)
|
|
|
|
|
+ .durationSec(durationSec)
|
|
|
|
|
+ .status(status)
|
|
|
|
|
+ .dataQualityStatus(dataQualityStatus)
|
|
|
|
|
+ .dataQualityCompletenessRate(completenessRate)
|
|
|
|
|
+ .createTime(LocalDateTime.now())
|
|
|
|
|
+ .build();
|
|
|
|
|
+ save(mainRecord);
|
|
|
|
|
+ Long resultId = mainRecord.getId();
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 写指标明细 — county 级
|
|
|
|
|
+ List<StaticIndicatorMetric> metricList = new ArrayList<StaticIndicatorMetric>();
|
|
|
|
|
+ if (countyResult != null) {
|
|
|
|
|
+ JSONArray categories = countyResult.getJSONArray("categories");
|
|
|
|
|
+ if (categories != null) {
|
|
|
|
|
+ for (int i = 0; i < categories.size(); i++) {
|
|
|
|
|
+ JSONObject category = categories.getJSONObject(i);
|
|
|
|
|
+ parseCategoryMetrics(category, resultId, "county", null, null, null, null, null, metricList);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 写指标明细 — feeder 级
|
|
|
|
|
+ if (calcResult != null) {
|
|
|
|
|
+ JSONArray feederResults = calcResult.getJSONArray("feeder_results");
|
|
|
|
|
+ if (feederResults != null) {
|
|
|
|
|
+ for (int i = 0; i < feederResults.size(); i++) {
|
|
|
|
|
+ JSONObject feeder = feederResults.getJSONObject(i);
|
|
|
|
|
+ String feederId = feeder.getString("feeder_id");
|
|
|
|
|
+ String feederName = feeder.getString("feeder_name");
|
|
|
|
|
+ String sourceSubstationName = feeder.getString("source_substation_name");
|
|
|
|
|
+ String sourceBusId = feeder.getString("source_bus_id");
|
|
|
|
|
+ String supplyAreaType = feeder.getString("supply_area_type");
|
|
|
|
|
+ JSONArray feederCategories = feeder.getJSONArray("categories");
|
|
|
|
|
+ if (feederCategories != null) {
|
|
|
|
|
+ for (int j = 0; j < feederCategories.size(); j++) {
|
|
|
|
|
+ JSONObject category = feederCategories.getJSONObject(j);
|
|
|
|
|
+ parseCategoryMetrics(category, resultId, "feeder", feederId,
|
|
|
|
|
+ feederName, sourceSubstationName, sourceBusId, supplyAreaType,
|
|
|
|
|
+ metricList);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ for (StaticIndicatorMetric m : metricList) {
|
|
|
|
|
+ metricMapper.insert(m);
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("静态网架指标明细入库完成 resultId={}, metricCount={}", resultId, metricList.size());
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 写问题详情
|
|
|
|
|
+ if (calcResult != null) {
|
|
|
|
|
+ JSONArray problemDetails = calcResult.getJSONArray("problem_details");
|
|
|
|
|
+ if (problemDetails != null) {
|
|
|
|
|
+ int problemCount = 0;
|
|
|
|
|
+ for (int i = 0; i < problemDetails.size(); i++) {
|
|
|
|
|
+ JSONObject p = problemDetails.getJSONObject(i);
|
|
|
|
|
+ JSONObject actualValues = p.getJSONObject("actual_values");
|
|
|
|
|
+ String actualValue = actualValues != null
|
|
|
|
|
+ ? JSON.toJSONString(actualValues.get("value")) : null;
|
|
|
|
|
+
|
|
|
|
|
+ StaticProblemDetail detail = StaticProblemDetail.builder()
|
|
|
|
|
+ .resultId(resultId)
|
|
|
|
|
+ .problemId(p.getString("problem_id"))
|
|
|
|
|
+ .feederId(p.getString("feeder_id"))
|
|
|
|
|
+ .categoryCode(p.getString("category_code"))
|
|
|
|
|
+ .categoryName(p.getString("category_name"))
|
|
|
|
|
+ .metricCode(p.getString("metric_code"))
|
|
|
|
|
+ .metricName(p.getString("metric_name"))
|
|
|
|
|
+ .severity(p.getString("severity"))
|
|
|
|
|
+ .objectType(p.getString("object_type"))
|
|
|
|
|
+ .objectId(p.getString("object_id"))
|
|
|
|
|
+ .actualValue(actualValue)
|
|
|
|
|
+ .description(p.getString("description"))
|
|
|
|
|
+ .suggestion(p.getString("suggestion"))
|
|
|
|
|
+ .build();
|
|
|
|
|
+ problemDetailMapper.insert(detail);
|
|
|
|
|
+ problemCount++;
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("静态网架问题详情入库完成 resultId={}, problemCount={}", resultId, problemCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("静态网架评估入库完成 batchId={}, countyId={}, resultId={}", batchId, countyId, resultId);
|
|
|
|
|
+ return resultId;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 解析一个 category 下的 metrics 数组,追加到 metricList
|
|
|
|
|
+ */
|
|
|
|
|
+ private void parseCategoryMetrics(JSONObject category, Long resultId, String level,
|
|
|
|
|
+ String feederId, String feederName,
|
|
|
|
|
+ String sourceSubstationName, String sourceBusId,
|
|
|
|
|
+ String supplyAreaType,
|
|
|
|
|
+ List<StaticIndicatorMetric> metricList) {
|
|
|
|
|
+ String categoryCode = category.getString("category_code");
|
|
|
|
|
+ String categoryName = category.getString("category_name");
|
|
|
|
|
+ JSONArray metrics = category.getJSONArray("metrics");
|
|
|
|
|
+ if (metrics == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ for (int i = 0; i < metrics.size(); i++) {
|
|
|
|
|
+ JSONObject m = metrics.getJSONObject(i);
|
|
|
|
|
+ Object valueObj = m.get("value");
|
|
|
|
|
+ String valueStr = valueObj == null ? null : String.valueOf(valueObj);
|
|
|
|
|
+
|
|
|
|
|
+ StaticIndicatorMetric metric = StaticIndicatorMetric.builder()
|
|
|
|
|
+ .resultId(resultId)
|
|
|
|
|
+ .level(level)
|
|
|
|
|
+ .feederId(feederId)
|
|
|
|
|
+ .feederName(feederName)
|
|
|
|
|
+ .sourceSubstationName(sourceSubstationName)
|
|
|
|
|
+ .sourceBusId(sourceBusId)
|
|
|
|
|
+ .supplyAreaType(supplyAreaType)
|
|
|
|
|
+ .categoryCode(categoryCode)
|
|
|
|
|
+ .categoryName(categoryName)
|
|
|
|
|
+ .metricCode(m.getString("metric_code"))
|
|
|
|
|
+ .metricName(m.getString("metric_name"))
|
|
|
|
|
+ .value(valueStr)
|
|
|
|
|
+ .unit(m.getString("unit"))
|
|
|
|
|
+ .resultClass(m.getString("result_class"))
|
|
|
|
|
+ .severity(m.getString("severity"))
|
|
|
|
|
+ .calculationStatus(m.getString("calculation_status"))
|
|
|
|
|
+ .isProblem(m.getBoolean("is_problem") != null && m.getBoolean("is_problem") ? 1 : 0)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ metricList.add(metric);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|