From cca46d159e786796869bef52d5535374261e5e0f Mon Sep 17 00:00:00 2001 From: tangwei Date: Tue, 11 Aug 2026 15:48:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=B1=BC=E5=AD=97?= =?UTF-8?q?=E5=85=B8=E6=96=B0=E5=A2=9E=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SdFishDictoryBController.java | 38 ++++++++++------ .../qgc_base/domain/SdFishDictoryB.java | 5 ++- .../service/ISdFishDictoryBService.java | 12 ++++++ .../service/impl/PatchUpdateHelper.java | 43 +++++++++++++++---- .../impl/SdFishDictoryBServiceImpl.java | 40 +++++++++++++++++ 5 files changed, 116 insertions(+), 22 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java index 981752a2..b78b83a4 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java @@ -20,10 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -88,9 +85,14 @@ public class SdFishDictoryBController { if (entity == null) { return ResponseResult.error("数据不能为空"); } - entity.setId(IdUtil.simpleUUID()); + entity.setId(IdUtil.fastUUID()); entity.setCode(entity.getId()); + // 名称重名校验 + if (sdFishDictoryBService.existsByName(entity.getName())) { + return ResponseResult.error("该鱼类名称已存在"); + } + // 上传文件并设置附件ID到实体 applyUploadedFiles(entity, files); @@ -109,23 +111,35 @@ public class SdFishDictoryBController { @RequestParam(value = "files", required = false) List files) { try { SdEngInfoBHOperateRequest request = objectMapper.readValue(dataStr, SdEngInfoBHOperateRequest.class); - SdFishDictoryB entity = request == null || request.getEngInfo() == null ? null - : objectMapper.convertValue(request.getEngInfo(), SdFishDictoryB.class); - if (entity == null || entity.getId() == null) { + Map engInfo = request == null ? null : request.getEngInfo(); + if (engInfo == null || engInfo.get("id") == null) { return ResponseResult.error("数据或ID不能为空"); } + // 名称重名校验(仅当本次修改了名称时校验) + Object newName = engInfo.get("name"); + if (newName != null && StrUtil.isNotBlank(newName.toString())) { + String name = newName.toString(); + if (sdFishDictoryBService.existsByNameExcludeId(name, (String) engInfo.get("id"))) { + return ResponseResult.error("该鱼类名称已存在"); + } + } + // 获取修改前的实体,用于后续清理旧文件 - SdFishDictoryB before = sdFishDictoryBService.getById(entity.getId()); + SdFishDictoryB before = sdFishDictoryBService.getById((String) engInfo.get("id")); List oldAttachmentIds = before != null ? collectAttachmentIds(before) : Collections.emptyList(); // 上传新文件并设置附件ID - applyUploadedFiles(entity, files); + SdFishDictoryB tempEntity = objectMapper.convertValue(engInfo, SdFishDictoryB.class); + applyUploadedFiles(tempEntity, files); + // 将文件处理后 inffile 合并回 patch map + engInfo.put("inffile", tempEntity.getInffile()); - boolean result = sdFishDictoryBService.update(entity, request.getSource()); + boolean result = sdFishDictoryBService.update(engInfo, request.getSource()); if (result) { // 清理被替换的旧文件 - deleteReplacedFiles(oldAttachmentIds, collectAttachmentIds(entity)); + SdFishDictoryB after = sdFishDictoryBService.getById((String) engInfo.get("id")); + deleteReplacedFiles(oldAttachmentIds, collectAttachmentIds(after)); } return result ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败"); } catch (Exception e) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFishDictoryB.java b/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFishDictoryB.java index f4a18c95..2f62b2cc 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFishDictoryB.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFishDictoryB.java @@ -21,7 +21,7 @@ public class SdFishDictoryB implements Serializable { private static final long serialVersionUID = 1L; /** 主键 */ - @TableId(type = IdType.ASSIGN_UUID) + @TableId(type = IdType.INPUT) @FieldChinese("主键") private String id; @@ -105,6 +105,9 @@ public class SdFishDictoryB implements Serializable { @FieldChinese("所属流域") private String rvcd; + @TableField(exist = false) + private String rvcdName; + /** 洄游习性 */ @FieldChinese("洄游习性") private String habitMigrat; diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdFishDictoryBService.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdFishDictoryBService.java index c687cc28..da9d7224 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdFishDictoryBService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdFishDictoryBService.java @@ -6,6 +6,7 @@ import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.qgc_base.domain.SdFishDictoryB; import java.util.List; +import java.util.Map; public interface ISdFishDictoryBService extends IService { @@ -16,10 +17,21 @@ public interface ISdFishDictoryBService extends IService { boolean add(SdFishDictoryB entity, String source); boolean update(SdFishDictoryB entity, String source); + boolean update(Map patchMap, String source) throws Exception; boolean delete(List ids, String source); SdFishDictoryB getById(String id); + /** + * 检查名称是否已存在(不过滤IS_DELETED,因为唯一约束不区分软删除) + */ + boolean existsByName(String name); + + /** + * 检查名称是否已被其他记录占用(排除指定ID) + */ + boolean existsByNameExcludeId(String name, String excludeId); + List findSimilarFish(String name, Integer limit); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/PatchUpdateHelper.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/PatchUpdateHelper.java index e4352b45..85f72a98 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/PatchUpdateHelper.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/PatchUpdateHelper.java @@ -49,6 +49,22 @@ public class PatchUpdateHelper { @Resource private DictCodeToNameConverter dictCodeToNameConverter; + /** + * 执行 patch 更新(默认主键字段为 "stcd")。 + * + * @see #execute(IService, Map, String, String, Class, Set, List, String) + */ + public boolean execute( + IService service, + Map engInfoPatch, + String source, + String tableName, + Class entityClass, + Set transientFields, + List codeToNameMetaList) throws Exception { + return execute(service, engInfoPatch, source, tableName, entityClass, transientFields, codeToNameMetaList, "stcd"); + } + /** * 执行 patch 更新:仅更新前端显式传入的字段(包括 null 值),未传入的字段保持原值。 * @@ -59,6 +75,7 @@ public class PatchUpdateHelper { * @param entityClass 实体类 * @param transientFields 需跳过的瞬态字段集合(如 @TableField(exist=false)、serialVersionUID) * @param codeToNameMetaList 字典代码转名称配置(用于操作日志) + * @param pkFieldName 主键 Java 字段名(如 "stcd"、"id") * @param 实体类型 * @return true=更新成功 * @throws Exception Jackson 类型转换异常等 @@ -70,27 +87,29 @@ public class PatchUpdateHelper { String tableName, Class entityClass, Set transientFields, - List codeToNameMetaList) throws Exception { + List codeToNameMetaList, + String pkFieldName) throws Exception { - String stcd = engInfoPatch == null ? null : (String) engInfoPatch.get("stcd"); - if (StrUtil.isBlank(stcd)) { - throw new BizException("站点编码不能为空"); + Object pkValue = engInfoPatch == null ? null : engInfoPatch.get(pkFieldName); + if (isEmptyPk(pkValue)) { + throw new BizException("主键不能为空"); } - T before = service.getById(stcd); + T before = service.getById((String) pkValue); if (before == null) { - throw new BizException("测站不存在: " + stcd); + throw new BizException("记录不存在: " + pkValue); } T after = entityClass.getDeclaredConstructor().newInstance(); BeanUtil.copyProperties(before, after); objectMapper.updateValue(after, engInfoPatch); + String pkColumn = StrUtil.toUnderlineCase(pkFieldName).toUpperCase(); UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("STCD", stcd); + updateWrapper.eq(pkColumn, pkValue); boolean hasUpdate = false; for (Field field : entityClass.getDeclaredFields()) { String fieldName = field.getName(); - if (transientFields.contains(fieldName) || "stcd".equals(fieldName)) { + if (transientFields.contains(fieldName) || pkFieldName.equals(fieldName)) { continue; } if (!engInfoPatch.containsKey(fieldName)) { @@ -114,8 +133,14 @@ public class PatchUpdateHelper { if (result) { dictCodeToNameConverter.convertCodeToName(before, codeToNameMetaList); dictCodeToNameConverter.convertCodeToName(after, codeToNameMetaList); - msOperationLogService.recordModifyDetailLog(stcd, tableName, before, after, source, codeToNameMetaList); + msOperationLogService.recordModifyDetailLog(String.valueOf(pkValue), tableName, before, after, source, codeToNameMetaList); } return result; } + + private boolean isEmptyPk(Object value) { + if (value == null) return true; + if (value instanceof String) return StrUtil.isBlank((String) value); + return false; + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFishDictoryBServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFishDictoryBServiceImpl.java index ffe6a682..270aaa7a 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFishDictoryBServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFishDictoryBServiceImpl.java @@ -1,6 +1,7 @@ package com.yfd.platform.qgc_base.service.impl; import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -36,6 +37,14 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl TRANSIENT_FIELDS = Set.of( + "typeName", "rareName", "specOriginName", "ptypeName", + "habitatName", "situationName", "resourceTypeName", "serialVersionUID" + ); /** * 代码转名称元数据配置列表(静态初始化) @@ -95,6 +104,14 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl patchMap, String source) throws Exception { + return patchUpdateHelper.execute( + this, patchMap, source, TABLE_NAME, SdFishDictoryB.class, + TRANSIENT_FIELDS, CODE_TO_NAME_META_LIST, "id"); + } + @Override @Transactional(rollbackFor = Exception.class) public boolean delete(List ids, String source) { @@ -116,6 +133,29 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl 0; } + @Override + public boolean existsByName(String name) { + if (!StringUtils.hasText(name)) { + return false; + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SdFishDictoryB::getName, name); + return count(wrapper) > 0; + } + + @Override + public boolean existsByNameExcludeId(String name, String excludeId) { + if (!StringUtils.hasText(name)) { + return false; + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SdFishDictoryB::getName, name); + if (StringUtils.hasText(excludeId)) { + wrapper.ne(SdFishDictoryB::getId, excludeId); + } + return count(wrapper) > 0; + } + @Override public SdFishDictoryB getById(String id) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();