From 186225b8922f162492478511d298fa319033c192 Mon Sep 17 00:00:00 2001 From: luoweijian <1329394916@qq.com> Date: Tue, 30 Jun 2026 15:50:33 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=9A=E7=B1=BB=E6=8E=A5=E5=8F=A3=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/project/base/domain/dto/BaseDTO.java | 2 + .../base/domain/entity/BaseEntity.java | 12 +++++ .../auth/DingTalkAuthenticationProvider.java | 5 ++- .../ding/domain/enums/UserRoleEnum.java | 5 ++- .../DraftReviewApplicationServiceImpl.java | 44 ++++--------------- .../controller/InformationController.java | 5 ++- .../information/domain/dto/DraftSaveDTO.java | 2 + ...aveDataExtractResultDomainServiceImpl.java | 18 +++++++- src/main/resources/application-test.yml | 2 +- 9 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/project/base/domain/dto/BaseDTO.java b/src/main/java/com/project/base/domain/dto/BaseDTO.java index 979f049..c67fd2d 100644 --- a/src/main/java/com/project/base/domain/dto/BaseDTO.java +++ b/src/main/java/com/project/base/domain/dto/BaseDTO.java @@ -24,6 +24,8 @@ public class BaseDTO { private Boolean deleted = StatusEnum.Normal.getValue(); + /** 当前登录用户是否有权限编辑(创建者或超级管理员) */ + private Boolean canEdit; public T toEntity(Supplier supplier) { T entity = supplier.get(); diff --git a/src/main/java/com/project/base/domain/entity/BaseEntity.java b/src/main/java/com/project/base/domain/entity/BaseEntity.java index 27e109e..586c81d 100644 --- a/src/main/java/com/project/base/domain/entity/BaseEntity.java +++ b/src/main/java/com/project/base/domain/entity/BaseEntity.java @@ -8,6 +8,7 @@ import com.project.base.domain.dto.BaseDTO; import com.project.base.domain.enums.StatusEnum; import com.project.ding.domain.entity.UserEntity; import com.project.ding.domain.service.UserBaseService; +import com.project.ding.utils.SecurityUtils; import jakarta.persistence.Column; import jakarta.persistence.Id; import jakarta.persistence.MappedSuperclass; @@ -67,6 +68,17 @@ public class BaseEntity implements Serializable { } catch (Exception ignored) { // 获取用户信息失败时不阻塞主流程 } + // 判断当前用户是否可编辑(创建者、管理员或超级管理员) + try { + String currentUserId = SecurityUtils.getUserId(); + boolean isCreator = StrUtil.equals(currentUserId, this.creatorId); + boolean isAdmin = SecurityUtils.hasRole("ROLE_ADMIN") + || SecurityUtils.hasRole("ROLE_SUPER_ADMIN"); + baseDTO.setCanEdit(isCreator || isAdmin); + } catch (Exception ignored) { + // 获取当前用户信息失败时默认不可编辑 + baseDTO.setCanEdit(false); + } } return dto; } diff --git a/src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java b/src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java index b607129..1697b97 100644 --- a/src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java +++ b/src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java @@ -52,7 +52,7 @@ public class DingTalkAuthenticationProvider implements AuthenticationProvider { dingUserSyncUtil.triggerSync(false); } - // 3. 分配角色:默认考生,白名单为管理员 + // 3. 分配角色:默认考生,白名单为管理员,admin_type=1 为超级管理员 List authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority("ROLE_CANDIDATE")); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); @@ -60,6 +60,9 @@ public class DingTalkAuthenticationProvider implements AuthenticationProvider { AdminWhiteListEntity existOne = whitelistMapper.selectOne(queryWrapper); if (Objects.nonNull(existOne)) { authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); + if (existOne.getAdminType() != null && existOne.getAdminType() == 1) { + authorities.add(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN")); + } } return new DingTalkAuthenticationToken(user, authorities); } diff --git a/src/main/java/com/project/ding/domain/enums/UserRoleEnum.java b/src/main/java/com/project/ding/domain/enums/UserRoleEnum.java index 684232a..d11e84a 100644 --- a/src/main/java/com/project/ding/domain/enums/UserRoleEnum.java +++ b/src/main/java/com/project/ding/domain/enums/UserRoleEnum.java @@ -7,7 +7,8 @@ import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor public enum UserRoleEnum implements HasValueEnum { - ROLE_CANDIDATE("考生") , - ROLE_ADMIN("管理员"); + ROLE_CANDIDATE("考生"), + ROLE_ADMIN("管理员"), + ROLE_SUPER_ADMIN("超级管理员"); private final String value; } diff --git a/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java b/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java index 91cf2e7..77c74c7 100644 --- a/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java +++ b/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java @@ -6,6 +6,7 @@ import com.project.base.config.CustomIdGenerator; import com.project.base.domain.result.Result; import com.project.information.application.DraftReviewApplicationService; import com.project.information.domain.dto.DraftSaveDTO; +import com.project.information.domain.dto.KnowledgePointDTO; import com.project.information.domain.entity.InformationEntity; import com.project.information.domain.entity.KnowledgeClusterEntity; import com.project.information.domain.entity.KnowledgePointDraftEntity; @@ -225,13 +226,7 @@ public class DraftReviewApplicationServiceImpl implements DraftReviewApplication /** * 触发语义聚类 - * 当前为 mock 实现(均分2个簇),算法服务就绪后替换为真实调用 - * - * 替换方式:将方法体改为: - * List kpList = knowledgePoints.stream() - * .map(entity -> entity.toDTO(KnowledgePointDTO::new)) - * .toList(); - * algorithmApplicationService.postToClusteringByInformationId(informationId, kpList); + * 调用算法服务进行真实聚类,回调结果由 saveClusterByInformationId 处理 */ private void triggerClustering(Long informationId, List knowledgePoints) { // 清理旧聚类数据 @@ -246,35 +241,12 @@ public class DraftReviewApplicationServiceImpl implements DraftReviewApplication return; } - // 均分为2个簇 - int mid = (int) Math.ceil(knowledgePoints.size() / 2.0); - List> groups = List.of( - knowledgePoints.subList(0, mid), - knowledgePoints.subList(mid, knowledgePoints.size()) - ); - - String[] topics = {"前端框架核心概念", "后端基础设施"}; - for (int i = 0; i < groups.size(); i++) { - List group = groups.get(i); - if (group.isEmpty()) { - continue; - } - - KnowledgeClusterEntity cluster = new KnowledgeClusterEntity(); - cluster.setInformationId(informationId); - cluster.setClusterTopic(topics[i % topics.length]); - cluster.setClusterSize(group.size()); - knowledgeClusterBaseService.save(cluster); - - // 回写 clusterId 到知识点 - List kpIds = group.stream().map(KnowledgePointEntity::getId).toList(); - knowledgePointBaseService.lambdaUpdate() - .in(KnowledgePointEntity::getId, kpIds) - .set(KnowledgePointEntity::getClusterId, cluster.getId()) - .update(); - } + // 转换为 DTO 并调用算法服务聚类 + List kpList = knowledgePoints.stream() + .map(entity -> entity.toDTO(KnowledgePointDTO::new)) + .toList(); + algorithmApplicationService.postToClusteringByInformationId(informationId, kpList); - log.info(">>> [Mock聚类] 完成, informationId={}, 知识点数={}, 簇数={}", - informationId, knowledgePoints.size(), groups.stream().filter(g -> !g.isEmpty()).count()); + log.info(">>> [聚类] 已请求算法服务聚类, informationId={}, 知识点数={}", informationId, knowledgePoints.size()); } } diff --git a/src/main/java/com/project/information/controller/InformationController.java b/src/main/java/com/project/information/controller/InformationController.java index e78096c..87e50c5 100644 --- a/src/main/java/com/project/information/controller/InformationController.java +++ b/src/main/java/com/project/information/controller/InformationController.java @@ -140,9 +140,10 @@ public class InformationController { @PostMapping("/draft/batchSaveAndConfirm") public Result batchSaveAndConfirm(Long informationId, @RequestParam("draftList") String draftListJson) throws Exception { // Postman form-data 会对 JSON 字符串做 URL 编码,先解码 - String decodedJson = java.net.URLDecoder.decode(draftListJson, java.nio.charset.StandardCharsets.UTF_8); +// String decodedJson = java.net.URLDecoder.decode(draftListJson, java.nio.charset.StandardCharsets.UTF_8); ObjectMapper objectMapper = new ObjectMapper(); - List draftList = objectMapper.readValue(decodedJson, + // 直接使用 draftListJson + List draftList = objectMapper.readValue(draftListJson, objectMapper.getTypeFactory().constructCollectionType(List.class, DraftSaveDTO.class)); return draftReviewApplicationService.batchSaveAndConfirm(informationId, draftList); } diff --git a/src/main/java/com/project/information/domain/dto/DraftSaveDTO.java b/src/main/java/com/project/information/domain/dto/DraftSaveDTO.java index 50ad3d4..edda64a 100644 --- a/src/main/java/com/project/information/domain/dto/DraftSaveDTO.java +++ b/src/main/java/com/project/information/domain/dto/DraftSaveDTO.java @@ -1,11 +1,13 @@ package com.project.information.domain.dto; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; /** * 草稿批量保存DTO */ @Data +@JsonIgnoreProperties(ignoreUnknown = true) // 关键:忽略未知的属性 public class DraftSaveDTO { /** 草稿ID(新增时为null) */ diff --git a/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java b/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java index 4886079..f40feb2 100644 --- a/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java +++ b/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java @@ -3,8 +3,11 @@ package com.project.interaction.domain.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.project.information.domain.entity.InformationEntity; import com.project.information.domain.entity.InformationFileEntity; import com.project.information.domain.enums.FileParseStatusEnum; +import com.project.information.domain.enums.InformationParseStatusEnum; +import com.project.information.domain.service.InformationBaseService; import com.project.information.domain.service.InformationFileBaseService; import com.project.interaction.domain.dto.AiExtractRequestDTO; import com.project.interaction.domain.dto.DataExtractCallbackDTO; @@ -29,6 +32,9 @@ public class SaveDataExtractResultDomainServiceImpl implements SaveDataExtractRe @Autowired private InformationFileBaseService informationFileBaseService; + @Autowired + private InformationBaseService informationBaseService; + @Autowired private PostToAiExtractDomainService postToAiExtractDomainService; @@ -73,10 +79,20 @@ public class SaveDataExtractResultDomainServiceImpl implements SaveDataExtractRe return; } - // 3. 所有子文件均已到达终态 + // 3. 所有子文件均已到达终态,判断是否全部成功 boolean allSuccess = allFiles.stream() .allMatch(f -> FileParseStatusEnum.Success.getValue().equals(f.getParseStatus())); + // 更新虚拟资料的解析状态(无论成功或失败都更新) + InformationEntity information = informationBaseService.getById(informationId); + if (information != null) { + information.setParseStatus(allSuccess + ? InformationParseStatusEnum.Success.getValue() + : InformationParseStatusEnum.Fail.getValue()); + informationBaseService.updateById(information); + log.info(">>> [数据服务回调] 虚拟资料 {} 解析状态已更新为: {}", informationId, information.getParseStatus()); + } + if (!allSuccess) { log.warn(">>> [数据服务回调] 虚拟资料 {} 下存在解析失败的子文件,跳过算法调用", informationId); return; diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 5ee6cbb..e30f88c 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -81,7 +81,7 @@ ding: noticeUrlPrefix: https://107pm707566hq.vicp.fun/ai-evaluator algo: clusterUrl: /semantic-cluster - baseUrl: http://127.0.0.1:8002 + baseUrl: http://172.16.204.50/cluster generateQuestionUrl: /v1/generate/questions_from_cluster apiUrl: http://127.0.0.1:8000 jwt: