1、优化

This commit is contained in:
2026-05-08 10:33:03 +08:00
parent f50dd02b7b
commit cb180a8771
2 changed files with 164 additions and 107 deletions

View File

@@ -47,13 +47,13 @@ public class BimController {
} }
@GetMapping("/progressData") @GetMapping("/progressData")
public Map<String, Object> getProgressData() { public Map<String, Object> getProgressData(@RequestParam String date) {
return progressDataService.getOrCreateTask(); return progressDataService.getOrCreateTask(date);
} }
@GetMapping("/progressData/{taskId}") @GetMapping("/progressData/result")
public Map<String, Object> getProgressDataResult(@PathVariable String taskId) { public Map<String, Object> getProgressDataResult(@RequestParam String date) {
return progressDataService.getTaskResult(taskId); return progressDataService.getTaskResultByDate(date);
} }
@PostMapping("/getPjDayListByPositionId") @PostMapping("/getPjDayListByPositionId")
@@ -100,4 +100,4 @@ public class BimController {
} }
return result; return result;
} }
} }

View File

@@ -1,37 +1,35 @@
package com.bim.api.service; package com.bim.api.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bim.api.entity.ActAmtResponse;
import com.bim.api.entity.PartCodeRelation; import com.bim.api.entity.PartCodeRelation;
import com.bim.api.entity.PjDayListResponse;
import com.bim.api.query.ProjectProgressParams;
import com.bim.api.mapper.PartCodeRelationMapper; import com.bim.api.mapper.PartCodeRelationMapper;
import com.bim.api.util.ThirdPartyAuthUtil; import com.bim.api.util.ThirdPartyAuthUtil;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.PostConstruct; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.time.format.DateTimeParseException;
import java.util.concurrent.ConcurrentHashMap; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service @Service
public class ProgressDataService extends ServiceImpl<PartCodeRelationMapper, PartCodeRelation> { public class ProgressDataService extends ServiceImpl<PartCodeRelationMapper, PartCodeRelation> {
private static final String PROJECT_ID = "5e4bde33ec084f1a8673eb59b190dce7"; private static final String PROJECT_ID = "5e4bde33ec084f1a8673eb59b190dce7";
private static final String KEY_TASK_STATUS = "progress:task:"; private static final String KEY_TASK_PREFIX = "progress:task:";
private static final String KEY_TASK_TOTAL = ":total"; private static final String KEY_PROCESSING_PREFIX = "progress:processing:";
private static final String KEY_TASK_CURRENT = ":current"; private static final String SUFFIX_STATUS = ":status";
private static final String KEY_TASK_RESULT = ":result"; private static final String SUFFIX_TOTAL = ":total";
private static final String KEY_PROCESSING = "progress:processing"; private static final String SUFFIX_CURRENT = ":current";
private static final String KEY_COMPLETED = "progress:completed"; private static final String SUFFIX_RESULT = ":result";
private static final String KEY_LATEST_TASK = "progress:latest:taskId"; private static final String SUFFIX_ERROR = ":error";
private static final String SUFFIX_RAW_ACT_AMT = ":rawActAmt";
private static final Map<String, String> TASK_STATUS_CACHE = new ConcurrentHashMap<>();
private final ThirdPartyAuthUtil thirdPartyAuthUtil; private final ThirdPartyAuthUtil thirdPartyAuthUtil;
private final RedisTemplate<String, Object> redisTemplate; private final RedisTemplate<String, Object> redisTemplate;
@@ -40,141 +38,200 @@ public class ProgressDataService extends ServiceImpl<PartCodeRelationMapper, Par
this.redisTemplate = redisTemplate; this.redisTemplate = redisTemplate;
} }
public Map<String, Object> getOrCreateTask() { public Map<String, Object> getOrCreateTask(String date) {
String normalizedDate = normalizeDate(date);
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
result.put("date", normalizedDate);
String latestTaskId = (String) redisTemplate.opsForValue().get(KEY_LATEST_TASK);
if (latestTaskId != null) { String status = getTaskStatusByDate(normalizedDate);
String status = getTaskStatus(latestTaskId); if ("COMPLETED".equals(status)) {
if ("COMPLETED".equals(status)) { result.put("status", "COMPLETED");
result.put("taskId", latestTaskId); return result;
result.put("status", "COMPLETED");
return result;
}
} }
String processingTaskId = (String) redisTemplate.opsForValue().get(KEY_PROCESSING); String processing = (String) redisTemplate.opsForValue().get(buildProcessingKey(normalizedDate));
if (processingTaskId != null) { if (processing != null) {
result.put("taskId", processingTaskId);
result.put("status", "PROCESSING"); result.put("status", "PROCESSING");
return result; return result;
} }
String taskId = UUID.randomUUID().toString().replace("-", ""); Boolean lockResult = redisTemplate.opsForValue().setIfAbsent(buildProcessingKey(normalizedDate), "1");
initTask(taskId); if (!Boolean.TRUE.equals(lockResult)) {
calculateProgressAsync(taskId); result.put("status", "PROCESSING");
return result;
result.put("taskId", taskId); }
initTask(normalizedDate);
calculateProgressAsync(normalizedDate);
result.put("status", "STARTED"); result.put("status", "STARTED");
return result; return result;
} }
public Map<String, Object> getTaskResult(String taskId) { public Map<String, Object> getTaskResultByDate(String date) {
String normalizedDate = normalizeDate(date);
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
result.put("date", normalizedDate);
String status = getTaskStatus(taskId);
result.put("taskId", taskId); String status = getTaskStatusByDate(normalizedDate);
result.put("status", status); result.put("status", status);
if (status == null) { if (status == null) {
result.put("status", "NOT_FOUND"); String processing = (String) redisTemplate.opsForValue().get(buildProcessingKey(normalizedDate));
result.put("status", processing != null ? "PROCESSING" : "NOT_FOUND");
return result; return result;
} }
Integer total = (Integer) redisTemplate.opsForValue().get(KEY_TASK_STATUS + taskId + KEY_TASK_TOTAL); Integer total = (Integer) redisTemplate.opsForValue().get(buildTaskKey(normalizedDate, SUFFIX_TOTAL));
Integer current = (Integer) redisTemplate.opsForValue().get(KEY_TASK_STATUS + taskId + KEY_TASK_CURRENT); Integer current = (Integer) redisTemplate.opsForValue().get(buildTaskKey(normalizedDate, SUFFIX_CURRENT));
result.put("total", total != null ? total : 0); result.put("total", total != null ? total : 0);
result.put("current", current != null ? current : 0); result.put("current", current != null ? current : 0);
double progress = 0; double progress = 0;
if (total != null && total > 0 && current != null) { if (total != null && total > 0 && current != null) {
progress = (double) current / total; progress = (double) current / total;
} }
result.put("progress", progress); result.put("progress", progress);
if ("COMPLETED".equals(status)) { if ("COMPLETED".equals(status)) {
Object data = redisTemplate.opsForValue().get(KEY_TASK_STATUS + taskId + KEY_TASK_RESULT); Object data = redisTemplate.opsForValue().get(buildTaskKey(normalizedDate, SUFFIX_RESULT));
result.put("data", data); result.put("data", data);
} }
if ("FAILED".equals(status)) {
Object error = redisTemplate.opsForValue().get(buildTaskKey(normalizedDate, SUFFIX_ERROR));
if (error != null) {
result.put("error", error);
}
}
return result; return result;
} }
private String getTaskStatus(String taskId) { private String normalizeDate(String date) {
if (taskId == null) return null; if (date == null || date.isBlank()) {
return TASK_STATUS_CACHE.get(taskId); throw new IllegalArgumentException("date cannot be blank, expected format: yyyy-MM-dd");
}
try {
return LocalDate.parse(date).toString();
} catch (DateTimeParseException e) {
throw new IllegalArgumentException("invalid date format, expected: yyyy-MM-dd");
}
} }
private void initTask(String taskId) { private String buildTaskKey(String date, String suffix) {
TASK_STATUS_CACHE.put(taskId, "STARTED"); return KEY_TASK_PREFIX + date + suffix;
redisTemplate.opsForValue().set(KEY_PROCESSING, taskId);
} }
private void calculateProgressAsync(String taskId) { private String buildProcessingKey(String date) {
TASK_STATUS_CACHE.put(taskId, "PROCESSING"); return KEY_PROCESSING_PREFIX + date;
}
private String getTaskStatusByDate(String date) {
return (String) redisTemplate.opsForValue().get(buildTaskKey(date, SUFFIX_STATUS));
}
private Map<String, Object> buildActAmtRequest(String projectId, String positionId, String period) {
Map<String, Object> request = new HashMap<>();
request.put("projectId", projectId);
request.put("positionId", positionId);
request.put("period", period);
return request;
}
private void initTask(String date) {
redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_STATUS), "STARTED");
redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_TOTAL), 0);
redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_CURRENT), 0);
redisTemplate.delete(buildTaskKey(date, SUFFIX_RESULT));
redisTemplate.delete(buildTaskKey(date, SUFFIX_ERROR));
redisTemplate.delete(buildTaskKey(date, SUFFIX_RAW_ACT_AMT));
}
private void calculateProgressAsync(String date) {
redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_STATUS), "PROCESSING");
new Thread(() -> { new Thread(() -> {
try { try {
List<PartCodeRelation> relations = list(); List<PartCodeRelation> relations = list();
int total = relations.size(); int total = relations.size();
redisTemplate.opsForValue().set(KEY_TASK_STATUS + taskId + KEY_TASK_TOTAL, total); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_TOTAL), total);
redisTemplate.opsForValue().set(KEY_TASK_STATUS + taskId + KEY_TASK_CURRENT, 0); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_CURRENT), 0);
List<Map<String, Object>> results = new ArrayList<>(); List<Map<String, Object>> results = new ArrayList<>();
List<Map<String, Object>> rawActAmtResults = new ArrayList<>();
int current = 0;
for (PartCodeRelation relation : relations) { for (PartCodeRelation relation : relations) {
Map<String, Object> item = new HashMap<>(); Map<String, Object> item = new HashMap<>();
item.put("partId", relation.getPartId()); item.put("partId", relation.getPartId());
item.put("codeData", relation.getCodeData()); item.put("codeData", relation.getCodeData());
try { try {
LocalDateTime createTime = relation.getCreateTime(); LocalDateTime createTime = relation.getCreateTime();
String period = createTime != null ? createTime.toString().replace("T", " ") : null; String originalPeriod = createTime != null ? createTime.toString().replace("T", " ") : null;
String positionId = relation.getPartId();
ProjectProgressParams params = new ProjectProgressParams(); String requestPeriod = date;
params.setProjectId(PROJECT_ID);
params.setPositionIds(relation.getPartId()); ActAmtResponse actAmtResponse = thirdPartyAuthUtil.findActAmtByPositionId(
params.setPeriod(period); PROJECT_ID,
positionId,
PjDayListResponse pjDayResponse = thirdPartyAuthUtil.findPjDayListByPositionId(params); requestPeriod
);
Map<String, Object> requestParams = new HashMap<>();
requestParams.put("projectId", PROJECT_ID);
requestParams.put("positionId", positionId);
requestParams.put("period", requestPeriod);
Map<String, Object> rawEntry = new HashMap<>();
rawEntry.put("partId", positionId);
rawEntry.put("period", requestPeriod);
rawEntry.put("originalPeriod", originalPeriod);
rawEntry.put("request", requestParams);
rawEntry.put("response", actAmtResponse);
rawActAmtResults.add(rawEntry);
double progressData = 0; double progressData = 0;
if (pjDayResponse != null && pjDayResponse.getData() != null && !pjDayResponse.getData().isEmpty()) { if (actAmtResponse != null && actAmtResponse.getData() != null && !actAmtResponse.getData().isEmpty()) {
PjDayListResponse.PjDayData dayData = pjDayResponse.getData().get(0); ActAmtResponse.ActAmtData dayData = actAmtResponse.getData().get(0);
Double totalNum = dayData.getMeteringNum(); Double actAmt = dayData.getActAmt();
Double meteringNum = dayData.getMeteringAmt(); Double meteringAmt = dayData.getMeteringAmt();
if (totalNum != null && meteringNum != null && meteringNum != 0) { if (actAmt != null && meteringAmt != null && meteringAmt != 0) {
progressData = totalNum / meteringNum; progressData = actAmt / meteringAmt;
} }
} }
item.put("progressData", progressData); item.put("progressData", progressData);
} catch (Exception e) { } catch (Exception e) {
item.put("progressData", 0); item.put("progressData", 0);
item.put("error", e.getMessage()); item.put("error", e.getMessage());
Map<String, Object> rawEntry = new HashMap<>();
rawEntry.put("partId", relation.getPartId());
rawEntry.put("request", buildActAmtRequest(PROJECT_ID, relation.getPartId(), date));
rawEntry.put("error", e.getMessage());
rawActAmtResults.add(rawEntry);
} }
results.add(item); results.add(item);
current++;
Integer current = (Integer) redisTemplate.opsForValue().get(KEY_TASK_STATUS + taskId + KEY_TASK_CURRENT); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_CURRENT), current);
redisTemplate.opsForValue().set(KEY_TASK_STATUS + taskId + KEY_TASK_CURRENT, current + 1);
} }
redisTemplate.opsForValue().set(KEY_TASK_STATUS + taskId + KEY_TASK_RESULT, results); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_RESULT), results);
redisTemplate.opsForValue().set(KEY_TASK_STATUS + taskId + KEY_TASK_CURRENT, total); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_RAW_ACT_AMT), rawActAmtResults);
redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_CURRENT), total);
redisTemplate.delete(KEY_PROCESSING); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_STATUS), "COMPLETED");
redisTemplate.opsForValue().set(KEY_COMPLETED, taskId); redisTemplate.delete(buildProcessingKey(date));
redisTemplate.opsForValue().set(KEY_LATEST_TASK, taskId);
TASK_STATUS_CACHE.put(taskId, "COMPLETED");
} catch (Exception e) { } catch (Exception e) {
TASK_STATUS_CACHE.put(taskId, "FAILED"); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_STATUS), "FAILED");
redisTemplate.delete(KEY_PROCESSING); redisTemplate.opsForValue().set(buildTaskKey(date, SUFFIX_ERROR), e.getMessage());
redisTemplate.delete(buildProcessingKey(date));
} }
}).start(); }).start();
} }
} }