|
|
@@ -21,7 +21,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.util.Date;
|
|
|
import java.util.LinkedHashMap;
|
|
|
@@ -49,6 +52,9 @@ public class DanReportUploadService {
|
|
|
@Resource
|
|
|
private FileStorageService fileStorageService;
|
|
|
|
|
|
+ @Resource
|
|
|
+ private StorageService storageService;
|
|
|
+
|
|
|
@Resource
|
|
|
private DimensionScoreService dimensionScoreService;
|
|
|
|
|
|
@@ -282,6 +288,95 @@ if (!DanReportUpload.DIM_MIND.equals(dimension) && !DanReportUpload.DIM_WISDOM.e
|
|
|
return Result.success(vo);
|
|
|
}
|
|
|
|
|
|
+ // 维护:按正确维度重新解析已入库 DAN 上传,并刷新关联结果/展示块/汇总/五维能量
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Result<Map<String, Object>> reparseUpload(Long uploadId, String dimension) {
|
|
|
+ DanReportUpload upload = uploadMapper.selectById(uploadId);
|
|
|
+ if (upload == null || upload.getDeletedAt() != null) {
|
|
|
+ return Result.error("上传记录不存在");
|
|
|
+ }
|
|
|
+ if (!DanReportUpload.DIM_MIND.equals(dimension) && !DanReportUpload.DIM_WISDOM.equals(dimension)
|
|
|
+ && !DanReportUpload.DIM_COGNITION.equals(dimension) && !DanReportUpload.DIM_LEARNING.equals(dimension)
|
|
|
+ && !DanReportUpload.DIM_BEHAVIOR.equals(dimension) && !DanReportUpload.DIM_CAREER.equals(dimension)
|
|
|
+ && !DanReportUpload.DIM_CAMPUS.equals(dimension) && !DanReportUpload.DIM_ADOLESCENT.equals(dimension)) {
|
|
|
+ return Result.error("dimension 非法: " + dimension);
|
|
|
+ }
|
|
|
+ File pdf;
|
|
|
+ try {
|
|
|
+ pdf = new File(storageService.getFilePath(upload.getFileUrl()));
|
|
|
+ } catch (Exception e) {
|
|
|
+ return Result.error("文件路径解析失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ if (!pdf.exists()) {
|
|
|
+ return Result.error("文件不存在: " + pdf.getAbsolutePath());
|
|
|
+ }
|
|
|
+ DanReportParseService.DanParsedReport parsed;
|
|
|
+ try (InputStream in = new FileInputStream(pdf)) {
|
|
|
+ parsed = danReportParseService.parse(in, dimension);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("DAN重解析失败 uploadId={}", uploadId, e);
|
|
|
+ return Result.error("解析失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ if (parsed == null || parsed.getItems() == null || parsed.getItems().isEmpty()) {
|
|
|
+ return Result.error("未能提取有效指标");
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ upload.setParsedItems(objectMapper.writeValueAsString(parsed.getItems()));
|
|
|
+ upload.setParsedExtra(objectMapper.writeValueAsString(parsed.getExtra()));
|
|
|
+ } catch (Exception e) {
|
|
|
+ return Result.error("序列化失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ upload.setDimension(dimension);
|
|
|
+ upload.setReportType(parsed.getReportType());
|
|
|
+ upload.setParsedSummary(parsed.getSummary());
|
|
|
+ upload.setParsedSuggestions(parsed.getSuggestions());
|
|
|
+ upload.setParsedAt(new Date());
|
|
|
+ upload.setUpdatedAt(new Date());
|
|
|
+ uploadMapper.updateById(upload);
|
|
|
+
|
|
|
+ Long resultId = upload.getLinkedResultId();
|
|
|
+ if (resultId != null) {
|
|
|
+ DanAssessmentResult result = resultMapper.selectById(resultId);
|
|
|
+ if (result != null) {
|
|
|
+ result.setDimension(dimension);
|
|
|
+ result.setStructuredAnalysis(upload.getParsedItems());
|
|
|
+ result.setAnalysisReport(upload.getParsedSummary());
|
|
|
+ result.setGrowthSuggestions(upload.getParsedSuggestions());
|
|
|
+ Integer overall = extractOverallScore(upload.getParsedItems());
|
|
|
+ if (overall != null) {
|
|
|
+ result.setOverallScore(overall);
|
|
|
+ result.setDanLevel(mapScoreToDanLevel(overall));
|
|
|
+ }
|
|
|
+ result.setUpdatedAt(new Date());
|
|
|
+ resultMapper.updateById(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ reportBlockService.save("dan", upload.getId(),
|
|
|
+ reportBlockAssembler.assembleDanByType(upload.getParsedItems(),
|
|
|
+ upload.getParsedSummary(), upload.getParsedSuggestions()));
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("DAN重解析保存展示块失败 uploadId={}: {}", uploadId, e.getMessage());
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ reportSummaryService.syncFromDanReport(upload);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("DAN重解析同步汇总失败 uploadId={}: {}", uploadId, e.getMessage());
|
|
|
+ }
|
|
|
+ if (resultId != null) {
|
|
|
+ try {
|
|
|
+ dimensionScoreService.refreshFromDanAssessment(upload.getFamilyMemberId(), resultId, dimension);
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Map<String, Object> data = new LinkedHashMap<>();
|
|
|
+ data.put("uploadId", upload.getId());
|
|
|
+ data.put("dimension", dimension);
|
|
|
+ data.put("reportType", upload.getReportType());
|
|
|
+ data.put("itemCount", parsed.getItems().size());
|
|
|
+ return Result.success(data);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* DAN 确认后自动生成方案,维度按测评维度映射(mind→mind,wisdom→wisdom)。
|
|
|
* 失败仅记日志,不阻断确认主流程。
|