From 65c1809e95ce373a9de94e0c800200ced7eeb66a Mon Sep 17 00:00:00 2001 From: zwt13703 Date: Sat, 14 Mar 2026 15:07:24 +0800 Subject: [PATCH] updates --- .../src/main/resources/application-dev.yml | 66 +- .../src/main/resources/application-test.yml | 66 +- .../art/controller/ArtTestController.java | 998 ++++++++++-------- 3 files changed, 599 insertions(+), 531 deletions(-) diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index c79507f..df26f24 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -8,9 +8,8 @@ spring.boot.admin.client: metadata: username: ${spring.boot.admin.client.username} userpassword: ${spring.boot.admin.client.password} - username: @monitor.username@ - password: @monitor.password@ - + username: ruoyi + password: 123456 --- # snail-job 配置 snail-job: enabled: ${SNAIL_JOB_ENABLED:false} @@ -27,7 +26,6 @@ snail-job: port: 2${server.port} # 客户端ip指定 host: - --- # 数据源配置 spring: datasource: @@ -42,40 +40,40 @@ spring: strict: true datasource: # 主库数据源 -# master: -# type: ${spring.datasource.type} -# driverClassName: com.mysql.cj.jdbc.Driver -# # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 -# # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) -# url: jdbc:mysql://10.13.13.1:3306/yitisheng_ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true -# username: root -# password: Db$7Hn#4Jm9Pq2!Xz -# # 从库数据源 -# slave: -# lazy: true -# type: ${spring.datasource.type} -# driverClassName: com.mysql.cj.jdbc.Driver -# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true -# username: -# password: -# oracle: -# type: ${spring.datasource.type} -# driverClassName: oracle.jdbc.OracleDriver -# url: jdbc:oracle:thin:@//localhost:1521/XE -# username: ROOT -# password: root + # master: + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + # url: jdbc:mysql://10.13.13.1:3306/yitisheng_ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: root + # password: Db$7Hn#4Jm9Pq2!Xz + # # 从库数据源 + # slave: + # lazy: true + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: + # password: + # oracle: + # type: ${spring.datasource.type} + # driverClassName: oracle.jdbc.OracleDriver + # url: jdbc:oracle:thin:@//localhost:1521/XE + # username: ROOT + # password: root postgres: type: ${spring.datasource.type} driverClassName: org.postgresql.Driver url: jdbc:postgresql://10.13.13.1:5432/art_sports_volunteer?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true username: art_sports_volunteer password: t56kX86WMQ8eNjRz -# sqlserver: -# type: ${spring.datasource.type} -# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver -# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true -# username: SA -# password: root + # sqlserver: + # type: ${spring.datasource.type} + # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver + # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true + # username: SA + # password: root hikari: # 最大连接池数量 maxPoolSize: 20 @@ -91,7 +89,6 @@ spring: maxLifetime: 1800000 # 多久检查一次连接的活性 keepaliveTime: 30000 - --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) spring.data: redis: @@ -138,7 +135,6 @@ mail: port: 465 # 是否需要用户名密码验证 auth: true - --- # 艺术院校导入配置 art: import: @@ -158,7 +154,6 @@ art: timeout: 0 # Socket连接超时值,单位毫秒,缺省值不超时 connectionTimeout: 0 - --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 sms: @@ -191,7 +186,6 @@ sms: signature: 您的短信签名 sdk-app-id: 您的sdkAppId - --- # 三方授权 justauth: # 前端外网访问地址 diff --git a/ruoyi-admin/src/main/resources/application-test.yml b/ruoyi-admin/src/main/resources/application-test.yml index c79507f..df26f24 100644 --- a/ruoyi-admin/src/main/resources/application-test.yml +++ b/ruoyi-admin/src/main/resources/application-test.yml @@ -8,9 +8,8 @@ spring.boot.admin.client: metadata: username: ${spring.boot.admin.client.username} userpassword: ${spring.boot.admin.client.password} - username: @monitor.username@ - password: @monitor.password@ - + username: ruoyi + password: 123456 --- # snail-job 配置 snail-job: enabled: ${SNAIL_JOB_ENABLED:false} @@ -27,7 +26,6 @@ snail-job: port: 2${server.port} # 客户端ip指定 host: - --- # 数据源配置 spring: datasource: @@ -42,40 +40,40 @@ spring: strict: true datasource: # 主库数据源 -# master: -# type: ${spring.datasource.type} -# driverClassName: com.mysql.cj.jdbc.Driver -# # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 -# # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) -# url: jdbc:mysql://10.13.13.1:3306/yitisheng_ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true -# username: root -# password: Db$7Hn#4Jm9Pq2!Xz -# # 从库数据源 -# slave: -# lazy: true -# type: ${spring.datasource.type} -# driverClassName: com.mysql.cj.jdbc.Driver -# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true -# username: -# password: -# oracle: -# type: ${spring.datasource.type} -# driverClassName: oracle.jdbc.OracleDriver -# url: jdbc:oracle:thin:@//localhost:1521/XE -# username: ROOT -# password: root + # master: + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + # url: jdbc:mysql://10.13.13.1:3306/yitisheng_ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: root + # password: Db$7Hn#4Jm9Pq2!Xz + # # 从库数据源 + # slave: + # lazy: true + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: + # password: + # oracle: + # type: ${spring.datasource.type} + # driverClassName: oracle.jdbc.OracleDriver + # url: jdbc:oracle:thin:@//localhost:1521/XE + # username: ROOT + # password: root postgres: type: ${spring.datasource.type} driverClassName: org.postgresql.Driver url: jdbc:postgresql://10.13.13.1:5432/art_sports_volunteer?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true username: art_sports_volunteer password: t56kX86WMQ8eNjRz -# sqlserver: -# type: ${spring.datasource.type} -# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver -# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true -# username: SA -# password: root + # sqlserver: + # type: ${spring.datasource.type} + # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver + # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true + # username: SA + # password: root hikari: # 最大连接池数量 maxPoolSize: 20 @@ -91,7 +89,6 @@ spring: maxLifetime: 1800000 # 多久检查一次连接的活性 keepaliveTime: 30000 - --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) spring.data: redis: @@ -138,7 +135,6 @@ mail: port: 465 # 是否需要用户名密码验证 auth: true - --- # 艺术院校导入配置 art: import: @@ -158,7 +154,6 @@ art: timeout: 0 # Socket连接超时值,单位毫秒,缺省值不超时 connectionTimeout: 0 - --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 sms: @@ -191,7 +186,6 @@ sms: signature: 您的短信签名 sdk-app-id: 您的sdkAppId - --- # 三方授权 justauth: # 前端外网访问地址 diff --git a/ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtTestController.java b/ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtTestController.java index c9bd5b0..2d4a6b7 100644 --- a/ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtTestController.java +++ b/ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtTestController.java @@ -2,24 +2,6 @@ package org.dromara.art.controller; import cn.hutool.core.collection.CollUtil; import com.fasterxml.jackson.databind.JsonNode; -import lombok.RequiredArgsConstructor; -import org.dromara.art.domain.bo.*; -import org.dromara.art.domain.vo.ArtSchoolImportDetailVo; -import org.dromara.art.domain.vo.ArtSchoolJsonImportPreviewVo; -import org.dromara.art.domain.vo.ArtSchoolVo; -import org.dromara.art.service.IArtSchoolDetailService; -import org.dromara.art.service.IArtSchoolService; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.json.utils.JsonUtils; -import org.dromara.common.core.domain.R; -import org.dromara.common.web.core.BaseController; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - import java.math.BigDecimal; import java.math.RoundingMode; import java.nio.file.Files; @@ -29,6 +11,23 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.stream.Stream; +import lombok.RequiredArgsConstructor; +import org.dromara.art.domain.bo.*; +import org.dromara.art.domain.vo.ArtSchoolImportDetailVo; +import org.dromara.art.domain.vo.ArtSchoolJsonImportPreviewVo; +import org.dromara.art.domain.vo.ArtSchoolVo; +import org.dromara.art.service.IArtSchoolDetailService; +import org.dromara.art.service.IArtSchoolService; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.web.core.BaseController; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; @Validated @RequiredArgsConstructor @@ -36,301 +35,366 @@ import java.util.stream.Stream; @RequestMapping("/art/test") public class ArtTestController extends BaseController { - private final IArtSchoolService artSchoolService; - private final IArtSchoolDetailService artSchoolDetailService; - @Value("${art.import.schoolJsonDir:}") - private String schoolJsonDir; + private final IArtSchoolService artSchoolService; + private final IArtSchoolDetailService artSchoolDetailService; - @GetMapping("/importSchoolByJson") - public R importSchoolByJson(@RequestParam(defaultValue = "20") Integer previewSize) { - int safePreviewSize = previewSize == null ? 20 : Math.min(Math.max(previewSize, 1), 200); - Path sourceDir; - if (StringUtils.isNotBlank(schoolJsonDir)) { - sourceDir = Path.of(schoolJsonDir.trim()); - } else { - sourceDir = Path.of(System.getProperty("user.dir"), "get_univ"); - } - if (!Files.exists(sourceDir) || !Files.isDirectory(sourceDir)) { - return R.fail("目录不存在: " + sourceDir); + @Value("${art.import.schoolJsonDir:}") + private String schoolJsonDir; + + @GetMapping("/importSchoolByJson") + public R importSchoolByJson( + @RequestParam(defaultValue = "20") Integer previewSize + ) { + int safePreviewSize = + previewSize == null ? 20 : Math.min(Math.max(previewSize, 1), 200); + Path sourceDir; + if (StringUtils.isNotBlank(schoolJsonDir)) { + sourceDir = Path.of(schoolJsonDir.trim()); + } else { + sourceDir = Path.of(System.getProperty("user.dir"), "get_univ"); + } + if (!Files.exists(sourceDir) || !Files.isDirectory(sourceDir)) { + return R.fail("目录不存在: " + sourceDir); + } + + List fileList; + try { + fileList = listJsonFiles(sourceDir); + } catch (RuntimeException e) { + return R.fail(e.getMessage()); + } + ArtSchoolJsonImportPreviewVo previewVo = new ArtSchoolJsonImportPreviewVo(); + previewVo.setSourceDir(sourceDir.toString()); + previewVo.setTotalFileCount(fileList.size()); + + List details = new ArrayList<>(); + List submitPreviewList = new ArrayList<>(); + Set fileUnivIdSet = new LinkedHashSet<>(); + Set fileMainCodeSet = new LinkedHashSet<>(); + + int readyCount = 0; + int duplicateInDbCount = 0; + int duplicateInFileCount = 0; + int invalidCount = 0; + int readFailCount = 0; + + for (Path file : fileList) { + String fileName = file.getFileName().toString(); + System.out.println("处理文件:" + fileName); + JsonNode root; + try { + root = JsonUtils.getObjectMapper().readTree(file.toFile()); + } catch (Exception e) { + readFailCount++; + appendDetail( + details, + safePreviewSize, + null, + null, + "FAILED", + fileName + " 读取失败: " + e.getMessage() + ); + continue; + } + + List schoolNodes = extractSchoolNodes(root); + if (CollUtil.isEmpty(schoolNodes)) { + invalidCount++; + appendDetail( + details, + safePreviewSize, + null, + null, + "INVALID", + fileName + " 缺少有效学校对象" + ); + continue; + } + + for (int i = 0; i < schoolNodes.size(); i++) { + JsonNode schoolNode = schoolNodes.get(i); + String sourceTag = + schoolNodes.size() == 1 ? fileName : (fileName + "#" + i); + + Integer univId = asInteger(schoolNode.get("univId")); + String mainName = asText(schoolNode.get("univName")); + if (univId == null || StringUtils.isBlank(mainName)) { + invalidCount++; + appendDetail( + details, + safePreviewSize, + null, + mainName, + "INVALID", + sourceTag + " 缺少必填字段: univId/univName" + ); + continue; } - List fileList; - try { - fileList = listJsonFiles(sourceDir); - } catch (RuntimeException e) { - return R.fail(e.getMessage()); + String mainCode = String.valueOf(univId); + if (!fileUnivIdSet.add(univId) || !fileMainCodeSet.add(mainCode)) { + duplicateInFileCount++; + appendDetail( + details, + safePreviewSize, + mainCode, + mainName, + "DUPLICATE_FILE", + sourceTag + " 文件内重复(univId/mainCode)" + ); + continue; } - ArtSchoolJsonImportPreviewVo previewVo = new ArtSchoolJsonImportPreviewVo(); - previewVo.setSourceDir(sourceDir.toString()); - previewVo.setTotalFileCount(fileList.size()); - List details = new ArrayList<>(); - List submitPreviewList = new ArrayList<>(); - Set fileUnivIdSet = new LinkedHashSet<>(); - Set fileMainCodeSet = new LinkedHashSet<>(); - - int readyCount = 0; - int duplicateInDbCount = 0; - int duplicateInFileCount = 0; - int invalidCount = 0; - int readFailCount = 0; - - for (Path file : fileList) { - String fileName = file.getFileName().toString(); - JsonNode root; - try { - root = JsonUtils.getObjectMapper().readTree(file.toFile()); - } catch (Exception e) { - readFailCount++; - appendDetail(details, safePreviewSize, null, null, "FAILED", fileName + " 读取失败: " + e.getMessage()); - continue; - } - - List schoolNodes = extractSchoolNodes(root); - if (CollUtil.isEmpty(schoolNodes)) { - invalidCount++; - appendDetail(details, safePreviewSize, null, null, "INVALID", fileName + " 缺少有效学校对象"); - continue; - } - - for (int i = 0; i < schoolNodes.size(); i++) { - JsonNode schoolNode = schoolNodes.get(i); - String sourceTag = schoolNodes.size() == 1 ? fileName : (fileName + "#" + i); - - Integer univId = asInteger(schoolNode.get("univId")); - String mainName = asText(schoolNode.get("univName")); - if (univId == null || StringUtils.isBlank(mainName)) { - invalidCount++; - appendDetail(details, safePreviewSize, null, mainName, "INVALID", sourceTag + " 缺少必填字段: univId/univName"); - continue; - } - - String mainCode = String.valueOf(univId); - if (!fileUnivIdSet.add(univId) || !fileMainCodeSet.add(mainCode)) { - duplicateInFileCount++; - appendDetail(details, safePreviewSize, mainCode, mainName, "DUPLICATE_FILE", sourceTag + " 文件内重复(univId/mainCode)"); - continue; - } - - /*if (existsInDatabase(mainCode, univId)) { + /*if (existsInDatabase(mainCode, univId)) { duplicateInDbCount++; appendDetail(details, safePreviewSize, mainCode, mainName, "DUPLICATE_DB", sourceTag + " 数据库已存在(mainCode 或 univId)"); continue; }*/ - ArtSchoolSubmitBo submitBo = buildSubmitBo(schoolNode, sourceTag, univId, mainCode, mainName); - readyCount++; - appendDetail(details, safePreviewSize, mainCode, mainName, "READY", sourceTag + " 已完成结构映射,待入库"); + ArtSchoolSubmitBo submitBo = buildSubmitBo( + schoolNode, + sourceTag, + univId, + mainCode, + mainName + ); + readyCount++; + appendDetail( + details, + safePreviewSize, + mainCode, + mainName, + "READY", + sourceTag + " 已完成结构映射,待入库" + ); - if (submitPreviewList.size() < safePreviewSize) { - submitPreviewList.add(toPreviewSubmitBo(submitBo)); - } - - // 预留真实入库调用(当前按要求先不入库) - // artSchoolService.insertWithDetailByBo(submitBo); - } + if (submitPreviewList.size() < safePreviewSize) { + submitPreviewList.add(toPreviewSubmitBo(submitBo)); } - for (ArtSchoolSubmitBo artSchoolSubmitBo : submitPreviewList) { - ArtSchoolBo artSchoolBo = new ArtSchoolBo(); - artSchoolBo.setMainName(artSchoolSubmitBo.getSchool().getMainName()); - List artSchoolVos = artSchoolService.queryList(artSchoolBo); - if (!artSchoolVos.isEmpty()) { - // 修改 - artSchoolSubmitBo.getSchool().setSchoolId(artSchoolVos.get(0).getSchoolId()); - artSchoolService.updateWithDetailByBo(artSchoolSubmitBo); - }else{ - artSchoolService.insertWithDetailByBo(artSchoolSubmitBo); - } - } - previewVo.setReadyCount(readyCount); - previewVo.setDuplicateInDbCount(duplicateInDbCount); - previewVo.setDuplicateInFileCount(duplicateInFileCount); - previewVo.setInvalidCount(invalidCount); - previewVo.setReadFailCount(readFailCount); - previewVo.setDetails(details); - previewVo.setSubmitPreviewList(submitPreviewList); - previewVo.setServiceCallHint("已预留调用: artSchoolService.insertWithDetailByBo(submitBo)"); - return R.ok(previewVo); + // 预留真实入库调用(当前按要求先不入库) + // artSchoolService.insertWithDetailByBo(submitBo); + } } - private List listJsonFiles(Path sourceDir) { - try (Stream stream = Files.list(sourceDir)) { - return stream - .filter(Files::isRegularFile) - .filter(path -> path.getFileName().toString().endsWith(".json")) - .sorted() - .toList(); - } catch (Exception e) { - throw new RuntimeException("读取目录失败: " + sourceDir, e); + for (ArtSchoolSubmitBo artSchoolSubmitBo : submitPreviewList) { + ArtSchoolBo artSchoolBo = new ArtSchoolBo(); + artSchoolBo.setMainName(artSchoolSubmitBo.getSchool().getMainName()); + List artSchoolVos = artSchoolService.queryList(artSchoolBo); + if (!artSchoolVos.isEmpty()) { + // 修改 + artSchoolSubmitBo + .getSchool() + .setSchoolId(artSchoolVos.get(0).getSchoolId()); + artSchoolService.updateWithDetailByBo(artSchoolSubmitBo); + } else { + artSchoolService.insertWithDetailByBo(artSchoolSubmitBo); + } + } + previewVo.setReadyCount(readyCount); + previewVo.setDuplicateInDbCount(duplicateInDbCount); + previewVo.setDuplicateInFileCount(duplicateInFileCount); + previewVo.setInvalidCount(invalidCount); + previewVo.setReadFailCount(readFailCount); + previewVo.setDetails(details); + previewVo.setSubmitPreviewList(submitPreviewList); + previewVo.setServiceCallHint( + "已预留调用: artSchoolService.insertWithDetailByBo(submitBo)" + ); + return R.ok(previewVo); + } + + private List listJsonFiles(Path sourceDir) { + try (Stream stream = Files.list(sourceDir)) { + return stream + .filter(Files::isRegularFile) + .filter(path -> path.getFileName().toString().endsWith(".json")) + .sorted() + .toList(); + } catch (Exception e) { + throw new RuntimeException("读取目录失败: " + sourceDir, e); + } + } + + private List extractSchoolNodes(JsonNode root) { + if (root == null || root.isNull()) { + return List.of(); + } + if (root.isArray()) { + List nodes = new ArrayList<>(); + for (JsonNode item : root) { + if (item != null && item.isObject()) { + nodes.add(item); } + } + return nodes; + } + if (root.isObject()) { + return List.of(root); + } + return List.of(); + } + + private boolean existsInDatabase(String mainCode, Integer univId) { + ArtSchoolBo schoolBo = new ArtSchoolBo(); + schoolBo.setMainCode(mainCode); + if (CollUtil.isNotEmpty(artSchoolService.queryList(schoolBo))) { + return true; + } + ArtSchoolDetailBo detailBo = new ArtSchoolDetailBo(); + detailBo.setUnivId(univId); + return CollUtil.isNotEmpty(artSchoolDetailService.queryList(detailBo)); + } + + private ArtSchoolSubmitBo buildSubmitBo( + JsonNode node, + String sourceTag, + Integer univId, + String mainCode, + String mainName + ) { + ArtSchoolBo school = new ArtSchoolBo(); + school.setMainCode(mainCode); + school.setMainName(mainName); + school.setProvince(asText(node.get("provId"))); // provName + school.setCity(asText(node.get("city"))); + school.setDistrict(null); + school.setUniversityType(asText(node.get("univTypeName"))); + school.setEducationLevel(resolveEducationLevel(node)); + //school.setSchoolNature(resolveSchoolNature(asInteger(node.get("isPublic")))); + school.setSupervisorDept(asText(node.get("competentDepart"))); + school.setRemark("source=" + sourceTag); + + ArtSchoolDetailBo detail = new ArtSchoolDetailBo(); + detail.setIntroduction(asText(node.get("univDesc"))); // 院校介绍 + detail.setSchoolIcon(asText(node.get("logo"))); // 校徽 + detail.setBackGround(asText(node.get("backGround"))); // 背景图 + detail.setAddress(asText(node.get("univAddress"))); // 详细地址 + detail.setContact(asText(node.get("contact"))); // 联系方式 + detail.setEmail(null); // 邮箱 + detail.setWebsite(asText(node.get("url"))); // 官方网址 + detail.setPostcode(null); + detail.setEstablishYear(asInteger(node.get("establishYear"))); + detail.setCampusAreaMu(null); + detail.setLibraryCollection(null); + BigDecimal femaleRatio = asDecimal(node.get("girlProportion")); + detail.setFemaleRatio(femaleRatio); + detail.setMaleRatio(resolveMaleRatio(femaleRatio)); + + detail.setIs985(normalizeFlag(asInteger(node.get("is985")))); + detail.setIs211(normalizeFlag(asInteger(node.get("is211")))); + detail.setIsDoubleFirstClass( + normalizeFlag(asInteger(node.get("isFirstClass"))) + ); + detail.setIsKeyUniversity( + normalizeFlag(asInteger(node.get("isFirstLevel"))) + ); + detail.setIsPublic(normalizeFlag(asInteger(node.get("isPublic")))); + + detail.setMasterProportionRate(asDecimal(node.get("masterProportion"))); // 考研率 + detail.setAbroadProportionRate(asDecimal(node.get("abroadProportion"))); // 出国率 + + detail.setHasRegular(normalizeFlag(asInteger(node.get("hasRegular")))); // 是否有本科 + detail.setHasJunior(normalizeFlag(asInteger(node.get("hasJunior")))); // 是否有专科 + detail.setHasMaster(normalizeFlag(asInteger(node.get("hasMaster")))); // 是否有研究生 + + detail.setIsDoubleHighPlan( + normalizeFlag(asInteger(node.get("isDoubleHighPlan"))) + ); // 是否双高计划(专科用) + detail.setIsStrongPlan(normalizeFlag(asInteger(node.get("isStrongPlan")))); // 是否强基计划 + detail.setTwsdlRank(normalizeFlag(asInteger(node.get("twsdl")))); + detail.setXyhRank(normalizeFlag(asInteger(node.get("xyh")))); + detail.setWslRank(normalizeFlag(asInteger(node.get("wsl")))); // 武书连排名 + detail.setUsdaluRank(normalizeFlag(asInteger(node.get("usdalu")))); // 美国大学排名相关 + detail.setQsdaluRank(normalizeFlag(asInteger(node.get("qsdalu")))); // QS世界大学排名 + + detail.setTags(buildTags(node)); + detail.setStudentCount(null); + detail.setTeacherCount(null); + detail.setMasterPoint(resolveMasterPoint(node)); + detail.setDoctorPoint(resolveDoctorPoint(node)); + detail.setKeyMajorCount(resolveKeyMajorCount(node)); + detail.setEmploymentRate(resolveEmploymentRate(node)); + detail.setSatisfactionRate(resolveSatisfactionRate(node)); + // 评分/满意度相关原始数据与明细保留,便于后续展示或二次计算 + detail.setCombinedScore(asDecimal(node.get("combinedScore"))); + detail.setOverallRank(asInteger(node.get("rank"))); + detail.setEnvSatisfaction(asDecimal(node.get("envSatisfaction"))); + detail.setEnvVote(asInteger(node.get("envVote"))); + detail.setLiveSatisfaction(asDecimal(node.get("liveSatisfaction"))); + detail.setLiveVote(asInteger(node.get("liveVote"))); + detail.setCombinedSatisfaction(asDecimal(node.get("combinedSatisfaction"))); + detail.setCombinedVote(asInteger(node.get("combinedVote"))); + detail.setSatisfactionJson(toJsonString(node.get("satisfactionJson"))); + detail.setTeachers(asText(node.get("teachers"))); + detail.setScholarship(asText(node.get("scholarship"))); + detail.setScholarshipJson(toJsonString(node.get("scholarshipArray"))); + detail.setGrantDesc(asText(node.get("grant"))); + detail.setCanteen(asText(node.get("canteen"))); + detail.setDormitory(asText(node.get("dormitory"))); + detail.setMasterExplain(asText(node.get("masterExplain"))); + detail.setDoctorExplain(asText(node.get("doctorExplain"))); + // 结构化内容以 JSON 文本落库,避免一次性拆表 + detail.setSpecialMajorJson(toJsonString(node.get("specialMajor"))); + detail.setEmploymentReportJson(toJsonString(node.get("employmentReport"))); + detail.setPhotoJson(toJsonString(node.get("photoJson"))); + detail.setAccommodationJson(toJsonString(node.get("accommodationArray"))); + detail.setSubjectReviewsJson(toJsonString(node.get("subjectReviews"))); + detail.setResearchJson(toJsonString(node.get("researchJson"))); + detail.setUnivMajorsJson(toJsonString(node.get("univMajors"))); + detail.setUnivPostgraduateJson( + toJsonString(node.get("univPostgraduateList")) + ); + detail.setUnivId(univId); + //detail.setRemark("source=" + sourceTag); + + ArtSchoolCollegeBo schoolCollegeBo = null; + List schoolCollegeBoList = new ArrayList<>(); + + ArtSchoolMajorBo artSchoolMajorBo = null; + List schoolMajorBoList; + // 学院信息 + for (JsonNode college : node.get("college")) { + schoolCollegeBo = new ArtSchoolCollegeBo(); + schoolCollegeBo.setCollegeName(asText(college.get("collegeName"))); + schoolCollegeBo.setCollege51sdxId(asInteger(college.get("collegeId"))); + + schoolMajorBoList = new ArrayList<>(); + // 学院专业列表 + if (college.has("majorList")) { + for (JsonNode major : college.get("majorList")) { + artSchoolMajorBo = new ArtSchoolMajorBo(); + artSchoolMajorBo.setEducationLevel( + "(本)".equals(asText(major.get("majorLevel"))) ? "1" : "0" + ); + artSchoolMajorBo.setMajorName(asText(major.get("majorName"))); + artSchoolMajorBo.setMajor51sdxId(asText(major.get("majorId"))); + schoolMajorBoList.add(artSchoolMajorBo); + } + schoolCollegeBo.setSchoolMajorBoList(schoolMajorBoList); + } + schoolCollegeBoList.add(schoolCollegeBo); } - private List extractSchoolNodes(JsonNode root) { - if (root == null || root.isNull()) { - return List.of(); - } - if (root.isArray()) { - List nodes = new ArrayList<>(); - for (JsonNode item : root) { - if (item != null && item.isObject()) { - nodes.add(item); - } - } - return nodes; - } - if (root.isObject()) { - return List.of(root); - } - return List.of(); - } + // 其余结构化内容已映射到详情 JSON 字段 - private boolean existsInDatabase(String mainCode, Integer univId) { - ArtSchoolBo schoolBo = new ArtSchoolBo(); - schoolBo.setMainCode(mainCode); - if (CollUtil.isNotEmpty(artSchoolService.queryList(schoolBo))) { - return true; - } - ArtSchoolDetailBo detailBo = new ArtSchoolDetailBo(); - detailBo.setUnivId(univId); - return CollUtil.isNotEmpty(artSchoolDetailService.queryList(detailBo)); - } + ArtSchoolSubmitBo submitBo = new ArtSchoolSubmitBo(); + submitBo.setSchool(school); + submitBo.setDetail(detail); + submitBo.setArtSchoolCollegeBoList(schoolCollegeBoList); + submitBo.setEnrollCodes(List.of()); + submitBo.setSchoolTags(List.of()); + return submitBo; + } - private ArtSchoolSubmitBo buildSubmitBo(JsonNode node, String sourceTag, Integer univId, String mainCode, String mainName) { - ArtSchoolBo school = new ArtSchoolBo(); - school.setMainCode(mainCode); - school.setMainName(mainName); - school.setProvince(asText(node.get("provId"))); // provName - school.setCity(asText(node.get("city"))); - school.setDistrict(null); - school.setUniversityType(asText(node.get("univTypeName"))); - school.setEducationLevel(resolveEducationLevel(node)); - //school.setSchoolNature(resolveSchoolNature(asInteger(node.get("isPublic")))); - school.setSupervisorDept(asText(node.get("competentDepart"))); - school.setRemark("source=" + sourceTag); - - ArtSchoolDetailBo detail = new ArtSchoolDetailBo(); - detail.setIntroduction(asText(node.get("univDesc"))); // 院校介绍 - detail.setSchoolIcon(asText(node.get("logo"))); // 校徽 - detail.setBackGround(asText(node.get("backGround"))); // 背景图 - detail.setAddress(asText(node.get("univAddress"))); // 详细地址 - detail.setContact(asText(node.get("contact"))); // 联系方式 - detail.setEmail(null); // 邮箱 - detail.setWebsite(asText(node.get("url"))); // 官方网址 - detail.setPostcode(null); - detail.setEstablishYear(asInteger(node.get("establishYear"))); - detail.setCampusAreaMu(null); - detail.setLibraryCollection(null); - BigDecimal femaleRatio = asDecimal(node.get("girlProportion")); - detail.setFemaleRatio(femaleRatio); - detail.setMaleRatio(resolveMaleRatio(femaleRatio)); - - detail.setIs985(normalizeFlag(asInteger(node.get("is985")))); - detail.setIs211(normalizeFlag(asInteger(node.get("is211")))); - detail.setIsDoubleFirstClass(normalizeFlag(asInteger(node.get("isFirstClass")))); - detail.setIsKeyUniversity(normalizeFlag(asInteger(node.get("isFirstLevel")))); - detail.setIsPublic(normalizeFlag(asInteger(node.get("isPublic")))); - - detail.setMasterProportionRate(asDecimal(node.get("masterProportion"))); // 考研率 - detail.setAbroadProportionRate(asDecimal(node.get("abroadProportion"))); // 出国率 - - detail.setHasRegular(normalizeFlag(asInteger(node.get("hasRegular")))); // 是否有本科 - detail.setHasJunior(normalizeFlag(asInteger(node.get("hasJunior")))); // 是否有专科 - detail.setHasMaster(normalizeFlag(asInteger(node.get("hasMaster")))); // 是否有研究生 - - detail.setIsDoubleHighPlan(normalizeFlag(asInteger(node.get("isDoubleHighPlan")))); // 是否双高计划(专科用) - detail.setIsStrongPlan(normalizeFlag(asInteger(node.get("isStrongPlan")))); // 是否强基计划 - detail.setTwsdlRank(normalizeFlag(asInteger(node.get("twsdl")))); - detail.setXyhRank(normalizeFlag(asInteger(node.get("xyh")))); - detail.setWslRank(normalizeFlag(asInteger(node.get("wsl")))); // 武书连排名 - detail.setUsdaluRank(normalizeFlag(asInteger(node.get("usdalu")))); // 美国大学排名相关 - detail.setQsdaluRank(normalizeFlag(asInteger(node.get("qsdalu")))); // QS世界大学排名 - - detail.setTags(buildTags(node)); - detail.setStudentCount(null); - detail.setTeacherCount(null); - detail.setMasterPoint(resolveMasterPoint(node)); - detail.setDoctorPoint(resolveDoctorPoint(node)); - detail.setKeyMajorCount(resolveKeyMajorCount(node)); - detail.setEmploymentRate(resolveEmploymentRate(node)); - detail.setSatisfactionRate(resolveSatisfactionRate(node)); - // 评分/满意度相关原始数据与明细保留,便于后续展示或二次计算 - detail.setCombinedScore(asDecimal(node.get("combinedScore"))); - detail.setOverallRank(asInteger(node.get("rank"))); - detail.setEnvSatisfaction(asDecimal(node.get("envSatisfaction"))); - detail.setEnvVote(asInteger(node.get("envVote"))); - detail.setLiveSatisfaction(asDecimal(node.get("liveSatisfaction"))); - detail.setLiveVote(asInteger(node.get("liveVote"))); - detail.setCombinedSatisfaction(asDecimal(node.get("combinedSatisfaction"))); - detail.setCombinedVote(asInteger(node.get("combinedVote"))); - detail.setSatisfactionJson(toJsonString(node.get("satisfactionJson"))); - detail.setTeachers(asText(node.get("teachers"))); - detail.setScholarship(asText(node.get("scholarship"))); - detail.setScholarshipJson(toJsonString(node.get("scholarshipArray"))); - detail.setGrantDesc(asText(node.get("grant"))); - detail.setCanteen(asText(node.get("canteen"))); - detail.setDormitory(asText(node.get("dormitory"))); - detail.setMasterExplain(asText(node.get("masterExplain"))); - detail.setDoctorExplain(asText(node.get("doctorExplain"))); - // 结构化内容以 JSON 文本落库,避免一次性拆表 - detail.setSpecialMajorJson(toJsonString(node.get("specialMajor"))); - detail.setEmploymentReportJson(toJsonString(node.get("employmentReport"))); - detail.setPhotoJson(toJsonString(node.get("photoJson"))); - detail.setAccommodationJson(toJsonString(node.get("accommodationArray"))); - detail.setSubjectReviewsJson(toJsonString(node.get("subjectReviews"))); - detail.setResearchJson(toJsonString(node.get("researchJson"))); - detail.setUnivMajorsJson(toJsonString(node.get("univMajors"))); - detail.setUnivPostgraduateJson(toJsonString(node.get("univPostgraduateList"))); - detail.setUnivId(univId); - //detail.setRemark("source=" + sourceTag); - - ArtSchoolCollegeBo schoolCollegeBo = null; - List schoolCollegeBoList = new ArrayList<>(); - - ArtSchoolMajorBo artSchoolMajorBo = null; - List schoolMajorBoList; - // 学院信息 - for (JsonNode college : node.get("college")) { - schoolCollegeBo = new ArtSchoolCollegeBo(); - schoolCollegeBo.setCollegeName(asText(college.get("collegeName"))); - schoolCollegeBo.setCollege51sdxId(asInteger(college.get("collegeId"))); - - schoolMajorBoList = new ArrayList<>(); - // 学院专业列表 - if (college.has("majorList")) { - for (JsonNode major : college.get("majorList")) { - artSchoolMajorBo = new ArtSchoolMajorBo(); - artSchoolMajorBo.setEducationLevel("(本)".equals(asText(major.get("majorLevel"))) ? "1" : "0"); - artSchoolMajorBo.setMajorName(asText(major.get("majorName"))); - artSchoolMajorBo.setMajor51sdxId(asText(major.get("majorId"))); - schoolMajorBoList.add(artSchoolMajorBo); - } - schoolCollegeBo.setSchoolMajorBoList(schoolMajorBoList); - } - schoolCollegeBoList.add(schoolCollegeBo); - } - - - - // 其余结构化内容已映射到详情 JSON 字段 - - ArtSchoolSubmitBo submitBo = new ArtSchoolSubmitBo(); - submitBo.setSchool(school); - submitBo.setDetail(detail); - submitBo.setArtSchoolCollegeBoList(schoolCollegeBoList); - submitBo.setEnrollCodes(List.of()); - submitBo.setSchoolTags(List.of()); - return submitBo; - } - - private ArtSchoolSubmitBo toPreviewSubmitBo(ArtSchoolSubmitBo submitBo) { - ArtSchoolSubmitBo preview = new ArtSchoolSubmitBo(); - preview.setSchool(submitBo.getSchool()); - ArtSchoolDetailBo detail = submitBo.getDetail(); - if (detail == null) { - preview.setDetail(null); - } else { - /*ArtSchoolDetailBo detailPreview = new ArtSchoolDetailBo(); + private ArtSchoolSubmitBo toPreviewSubmitBo(ArtSchoolSubmitBo submitBo) { + ArtSchoolSubmitBo preview = new ArtSchoolSubmitBo(); + preview.setSchool(submitBo.getSchool()); + ArtSchoolDetailBo detail = submitBo.getDetail(); + if (detail == null) { + preview.setDetail(null); + } else { + /*ArtSchoolDetailBo detailPreview = new ArtSchoolDetailBo(); detailPreview.setUnivId(detail.getUnivId()); detailPreview.setSchoolIcon(detail.getSchoolIcon()); detailPreview.setAddress(detail.getAddress()); @@ -350,195 +414,211 @@ public class ArtTestController extends BaseController { detailPreview.setSatisfactionRate(detail.getSatisfactionRate()); detailPreview.setTags(detail.getTags()); detailPreview.setRemark(detail.getRemark());*/ - preview.setDetail(submitBo.getDetail()); - } - preview.setArtSchoolCollegeBoList(submitBo.getArtSchoolCollegeBoList()); - preview.setEnrollCodes(submitBo.getEnrollCodes()); - preview.setSchoolTags(submitBo.getSchoolTags()); - return preview; + preview.setDetail(submitBo.getDetail()); } + preview.setArtSchoolCollegeBoList(submitBo.getArtSchoolCollegeBoList()); + preview.setEnrollCodes(submitBo.getEnrollCodes()); + preview.setSchoolTags(submitBo.getSchoolTags()); + return preview; + } - private String[] buildTags(JsonNode node) { - Set tags = new LinkedHashSet<>(); - if (isPositive(node.get("is985"))) { - tags.add("985"); - } - if (isPositive(node.get("is211"))) { - tags.add("211"); - } - if (isPositive(node.get("isFirstClass"))) { - tags.add("双一流"); - } - String typeName = asText(node.get("univTypeName")); - if (StringUtils.isNotBlank(typeName)) { - tags.add(typeName); - } - return tags.isEmpty() ? null : tags.toArray(String[]::new); + private String[] buildTags(JsonNode node) { + Set tags = new LinkedHashSet<>(); + if (isPositive(node.get("is985"))) { + tags.add("985"); } - - private Integer resolveMasterPoint(JsonNode node) { - Integer mastersDegree = asInteger(node.get("mastersDegree")); - if (mastersDegree != null) { - return mastersDegree; - } - Integer shuoshidian = asInteger(node.get("shuoshidian")); - if (shuoshidian != null) { - return shuoshidian; - } - return asInteger(node.path("researchJson").path("base").get("硕士点数量")); + if (isPositive(node.get("is211"))) { + tags.add("211"); } - - private Integer resolveDoctorPoint(JsonNode node) { - Integer doctoralProgram = asInteger(node.get("doctoralProgram")); - if (doctoralProgram != null) { - return doctoralProgram; - } - Integer boshidian = asInteger(node.get("boshidian")); - if (boshidian != null) { - return boshidian; - } - return asInteger(node.path("researchJson").path("base").get("博士点数量")); + if (isPositive(node.get("isFirstClass"))) { + tags.add("双一流"); } - - private Integer resolveKeyMajorCount(JsonNode node) { - Integer specialMajorCount = asInteger(node.get("specialMajorCount")); - if (specialMajorCount != null) { - return specialMajorCount; - } - Integer guojiatese = asInteger(node.get("guojiatese")); - if (guojiatese != null) { - return guojiatese; - } - return asInteger(node.path("researchJson").path("base").get("重点专业数量")); + String typeName = asText(node.get("univTypeName")); + if (StringUtils.isNotBlank(typeName)) { + tags.add(typeName); } + return tags.isEmpty() ? null : tags.toArray(String[]::new); + } - private BigDecimal resolveEmploymentRate(JsonNode node) { - BigDecimal employmentRate = asDecimal(node.get("jiuyelu")); - return employmentRate == null ? null : employmentRate.setScale(2, RoundingMode.HALF_UP); + private Integer resolveMasterPoint(JsonNode node) { + Integer mastersDegree = asInteger(node.get("mastersDegree")); + if (mastersDegree != null) { + return mastersDegree; } - - private BigDecimal resolveSatisfactionRate(JsonNode node) { - BigDecimal score = asDecimal(node.get("combinedSatisfaction")); - if (score == null) { - return null; - } - if (score.compareTo(new BigDecimal("5")) <= 0) { - return score.multiply(new BigDecimal("20")).setScale(2, RoundingMode.HALF_UP); - } - return score.setScale(2, RoundingMode.HALF_UP); + Integer shuoshidian = asInteger(node.get("shuoshidian")); + if (shuoshidian != null) { + return shuoshidian; } + return asInteger(node.path("researchJson").path("base").get("硕士点数量")); + } - private BigDecimal resolveMaleRatio(BigDecimal femaleRatio) { - if (femaleRatio == null) { - return null; - } - return new BigDecimal("100").subtract(femaleRatio).setScale(2, RoundingMode.HALF_UP); + private Integer resolveDoctorPoint(JsonNode node) { + Integer doctoralProgram = asInteger(node.get("doctoralProgram")); + if (doctoralProgram != null) { + return doctoralProgram; } - - private String resolveEducationLevel(JsonNode node) { - Integer hasRegular = asInteger(node.get("hasRegular")); - Integer hasJunior = asInteger(node.get("hasJunior")); - boolean regular = hasRegular != null && hasRegular == 1; - boolean junior = hasJunior != null && hasJunior == 1; - if (regular && junior) { - return "本科/专科"; - } - if (regular) { - return "本科"; - } - if (junior) { - return "专科"; - } - return null; + Integer boshidian = asInteger(node.get("boshidian")); + if (boshidian != null) { + return boshidian; } + return asInteger(node.path("researchJson").path("base").get("博士点数量")); + } - private String resolveSchoolNature(Integer isPublic) { - if (isPublic == null) { - return null; - } - if (isPublic == 1) { - return "公办"; - } - if (isPublic == 2) { - return "民办"; - } - return null; + private Integer resolveKeyMajorCount(JsonNode node) { + Integer specialMajorCount = asInteger(node.get("specialMajorCount")); + if (specialMajorCount != null) { + return specialMajorCount; } - - private boolean isPositive(JsonNode node) { - Integer value = asInteger(node); - return value != null && value > 0; + Integer guojiatese = asInteger(node.get("guojiatese")); + if (guojiatese != null) { + return guojiatese; } + return asInteger( + node.path("researchJson").path("base").get("重点专业数量") + ); + } - private Integer normalizeFlag(Integer value) { - if (value == null) { - return 0; - } - return value > 0 ? 1 : 0; + private BigDecimal resolveEmploymentRate(JsonNode node) { + BigDecimal employmentRate = asDecimal(node.get("jiuyelu")); + return employmentRate == null + ? null + : employmentRate.setScale(2, RoundingMode.HALF_UP); + } + + private BigDecimal resolveSatisfactionRate(JsonNode node) { + BigDecimal score = asDecimal(node.get("combinedSatisfaction")); + if (score == null) { + return null; } - - private String asText(JsonNode node) { - if (node == null || node.isNull()) { - return null; - } - String text = node.asText(); - if (StringUtils.isBlank(text)) { - return null; - } - return text.trim(); + if (score.compareTo(new BigDecimal("5")) <= 0) { + return score + .multiply(new BigDecimal("20")) + .setScale(2, RoundingMode.HALF_UP); } + return score.setScale(2, RoundingMode.HALF_UP); + } - private Integer asInteger(JsonNode node) { - if (node == null || node.isNull()) { - return null; - } - if (node.isNumber()) { - return node.intValue(); - } - String text = asText(node); - if (StringUtils.isBlank(text)) { - return null; - } - try { - return Integer.valueOf(text.replace("%", "").trim()); - } catch (Exception e) { - return null; - } + private BigDecimal resolveMaleRatio(BigDecimal femaleRatio) { + if (femaleRatio == null) { + return null; } + return new BigDecimal("100") + .subtract(femaleRatio) + .setScale(2, RoundingMode.HALF_UP); + } - private BigDecimal asDecimal(JsonNode node) { - if (node == null || node.isNull()) { - return null; - } - String text = node.isNumber() ? node.numberValue().toString() : asText(node); - if (StringUtils.isBlank(text)) { - return null; - } - try { - return new BigDecimal(text.replace("%", "").trim()); - } catch (Exception e) { - return null; - } + private String resolveEducationLevel(JsonNode node) { + Integer hasRegular = asInteger(node.get("hasRegular")); + Integer hasJunior = asInteger(node.get("hasJunior")); + boolean regular = hasRegular != null && hasRegular == 1; + boolean junior = hasJunior != null && hasJunior == 1; + if (regular && junior) { + return "本科/专科"; } - - private String toJsonString(JsonNode node) { - if (node == null || node.isNull()) { - return null; - } - // 统一走 ObjectMapper 序列化,保持 JSON 原始结构 - return JsonUtils.toJsonString(node); + if (regular) { + return "本科"; } - - private void appendDetail(List details, int maxSize, String mainCode, String mainName, String status, String message) { - if (details.size() >= maxSize) { - return; - } - ArtSchoolImportDetailVo detailVo = new ArtSchoolImportDetailVo(); - detailVo.setMainCode(mainCode); - detailVo.setMainName(mainName); - detailVo.setStatus(status); - detailVo.setMessage(message); - details.add(detailVo); + if (junior) { + return "专科"; } + return null; + } + private String resolveSchoolNature(Integer isPublic) { + if (isPublic == null) { + return null; + } + if (isPublic == 1) { + return "公办"; + } + if (isPublic == 2) { + return "民办"; + } + return null; + } + + private boolean isPositive(JsonNode node) { + Integer value = asInteger(node); + return value != null && value > 0; + } + + private Integer normalizeFlag(Integer value) { + if (value == null) { + return 0; + } + return value > 0 ? 1 : 0; + } + + private String asText(JsonNode node) { + if (node == null || node.isNull()) { + return null; + } + String text = node.asText(); + if (StringUtils.isBlank(text)) { + return null; + } + return text.trim(); + } + + private Integer asInteger(JsonNode node) { + if (node == null || node.isNull()) { + return null; + } + if (node.isNumber()) { + return node.intValue(); + } + String text = asText(node); + if (StringUtils.isBlank(text)) { + return null; + } + try { + return Integer.valueOf(text.replace("%", "").trim()); + } catch (Exception e) { + return null; + } + } + + private BigDecimal asDecimal(JsonNode node) { + if (node == null || node.isNull()) { + return null; + } + String text = node.isNumber() + ? node.numberValue().toString() + : asText(node); + if (StringUtils.isBlank(text)) { + return null; + } + try { + return new BigDecimal(text.replace("%", "").trim()); + } catch (Exception e) { + return null; + } + } + + private String toJsonString(JsonNode node) { + if (node == null || node.isNull()) { + return null; + } + // 统一走 ObjectMapper 序列化,保持 JSON 原始结构 + return JsonUtils.toJsonString(node); + } + + private void appendDetail( + List details, + int maxSize, + String mainCode, + String mainName, + String status, + String message + ) { + if (details.size() >= maxSize) { + return; + } + ArtSchoolImportDetailVo detailVo = new ArtSchoolImportDetailVo(); + detailVo.setMainCode(mainCode); + detailVo.setMainName(mainName); + detailVo.setStatus(status); + detailVo.setMessage(message); + details.add(detailVo); + } }