Pārlūkot izejas kodu

feat(mall): 添加分类设置状态修改功能并优化远程分类同步逻辑

- 在 DkhCategoryMainController 中新增 changeStatus 接口用于修改分类状态
- 重构远程分类树构建逻辑,移除 nameToSyncId 映射参数,直接从 JSON 的 syncCategoryId 字段获取远程 ID
- 新增 getSyncCategoryIdFromNode 方法处理远程同步 ID 的获取逻辑
- 在构建分类树时回写 syncCategoryId 到 panelConfigJson,使前端能够获取远程 ID
- 修改 SysAnnouncement 实体类中 coverImage 字段类型从 Long 改为 String
- 移除 SysAnnouncementVo 中 coverImageUrl 的翻译注解,调整字段类型一致性
hurx 7 stundas atpakaļ
vecāks
revīzija
cf0d5c6c7d

+ 9 - 0
ruoyi-modules/ruoyi-mall/src/main/java/org/dromara/mall/controller/DkhCategoryMainController.java

@@ -103,4 +103,13 @@ public class DkhCategoryMainController extends BaseController {
                           @PathVariable("ids") Long[] ids) {
         return toAjax(dkhCategoryMainService.deleteWithValidByIds(List.of(ids), true));
     }
+
+    /**
+     * 状态修改
+     */
+    @Log(title = "分类设置", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody DkhCategoryMainBo bo) {
+        return toAjax(dkhCategoryMainService.updateStatus(bo));
+    }
 }

+ 8 - 0
ruoyi-modules/ruoyi-mall/src/main/java/org/dromara/mall/service/IDkhCategoryMainService.java

@@ -59,6 +59,14 @@ public interface IDkhCategoryMainService extends IService<DkhCategoryMain>{
      */
     Boolean updateByBo(DkhCategoryMainBo bo);
 
+    /**
+     * 修改状态
+     *
+     * @param bo 包含 id 和 status
+     * @return 是否修改成功
+     */
+    Boolean updateStatus(DkhCategoryMainBo bo);
+
     /**
      * 校验并批量删除分类设置主信息
      *

+ 53 - 39
ruoyi-modules/ruoyi-mall/src/main/java/org/dromara/mall/service/impl/DkhCategoryMainServiceImpl.java

@@ -268,29 +268,17 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
             DkhCategoryMain dbRecord = baseMapper.selectById(update.getId());
             Long syncCategoryId = dbRecord != null ? dbRecord.getSyncCategoryId() : bo.getSyncCategoryId();
 
-            // 查询旧子菜单,构建 name→syncCategoryId 映射,用于远程增量更新时匹配已有分类
-            List<DkhCategorySub> oldSubs = categorySubMapper.selectList(
-                Wrappers.<DkhCategorySub>lambdaQuery()
-                    .eq(DkhCategorySub::getMainCategoryId, update.getId()));
-            Map<String, Long> oldNameToSyncId = new HashMap<>();
-            for (DkhCategorySub sub : oldSubs) {
-                if (sub.getSyncCategoryId() != null && StringUtils.isNotBlank(sub.getName())) {
-                    oldNameToSyncId.put(sub.getLevel() + ":" + sub.getName(), sub.getSyncCategoryId());
-                }
-            }
-
             if (syncCategoryId != null && StringUtils.isNotBlank(bo.getPanelConfigJson())) {
                 try {
                     JsonNode rootNode = objectMapper.readTree(bo.getPanelConfigJson());
                     JsonNode subMenus = rootNode.get("subMenus");
 
                     if (subMenus != null && subMenus.isArray()) {
-                        // 用旧记录的 syncCategoryId 填充 CategoryDto 的 ID,实现远程增量更新
+                        // 直接用 panelConfigJson 中的 syncCategoryId 构建分类树,实现远程增量更新
                         List<CategoryDto> newCategoryTree = buildCategoryTreeFromSubMenus(
                             bo.getName(),
                             subMenus,
-                            syncCategoryId,
-                            oldNameToSyncId
+                            syncCategoryId
                         );
                         remoteCategoryService.updateCategoryTree(syncCategoryId, newCategoryTree);
                     }
@@ -323,7 +311,7 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
     /**
      * 从 subMenus 构建分类树 DTO 列表(树形结构)
      */
-    private List<CategoryDto> buildCategoryTreeFromSubMenus(String categoryName, JsonNode subMenus, Long rootCategoryId, Map<String, Long> nameToSyncId) {
+    private List<CategoryDto> buildCategoryTreeFromSubMenus(String categoryName, JsonNode subMenus, Long rootCategoryId) {
         List<CategoryDto> result = new ArrayList<>();
 
         CategoryDto rootDto = new CategoryDto();
@@ -341,12 +329,12 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
                     JsonNode nestedChildren = level2Node.get("children");
                     if (nestedChildren != null && nestedChildren.isArray()) {
                         for (JsonNode nestedChild : nestedChildren) {
-                            level2Children.add(buildCategoryDtoFromNode(nestedChild, rootCategoryId, 2L, nameToSyncId));
+                            level2Children.add(buildCategoryDtoFromNode(nestedChild, rootCategoryId, 2L));
                         }
                     }
                     continue;
                 }
-                level2Children.add(buildCategoryDtoFromNode(level2Node, rootCategoryId, 2L, nameToSyncId));
+                level2Children.add(buildCategoryDtoFromNode(level2Node, rootCategoryId, 2L));
             }
         }
 
@@ -356,21 +344,16 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
     }
 
     /**
-     * 从 JSON 节点构建 CategoryDto(递归),优先从 nameToSyncId 映射获取 ID
+     * 从 JSON 节点构建 CategoryDto(递归),直接从 syncCategoryId 字段获取远程真实ID
      */
-    private CategoryDto buildCategoryDtoFromNode(JsonNode node, Long parentId, Long classLevel, Map<String, Long> nameToSyncId) {
+    private CategoryDto buildCategoryDtoFromNode(JsonNode node, Long parentId, Long classLevel) {
         CategoryDto dto = new CategoryDto();
 
-        // 优先使用 JSON 中的 id,其次从旧记录的 syncCategoryId 映射中查找
-        if (node.has("id") && node.get("id").asLong() > 0) {
-            dto.setId(node.get("id").asLong());
-        } else if (nameToSyncId != null) {
-            String name = node.has("name") ? node.get("name").asText() : null;
-            if (StringUtils.isNotBlank(name)) {
-                Long syncId = nameToSyncId.get(classLevel + ":" + name);
-                if (syncId != null) {
-                    dto.setId(syncId);
-                }
+        // 从 panelConfigJson 中的 syncCategoryId 字段读取真实远程ID
+        if (node.has("syncCategoryId") && !node.get("syncCategoryId").isNull()) {
+            String syncIdStr = node.get("syncCategoryId").asText();
+            if (StringUtils.isNotBlank(syncIdStr)) {
+                dto.setId(Long.valueOf(syncIdStr));
             }
         }
 
@@ -387,7 +370,7 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
             List<CategoryDto> children = new ArrayList<>();
             for (JsonNode childNode : childrenNode) {
                 children.add(buildCategoryDtoFromNode(childNode,
-                    dto.getId() != null ? dto.getId() : parentId, classLevel + 1, nameToSyncId));
+                    dto.getId() != null ? dto.getId() : parentId, classLevel + 1));
             }
             dto.setChildren(children);
         }
@@ -411,6 +394,7 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
                 if (subMenus != null && subMenus.isArray()) {
                     for (JsonNode level2Node : subMenus) {
                         String level2Name = level2Node.has("name") ? level2Node.get("name").asText() : null;
+                        Long level2SyncId = getSyncCategoryIdFromNode(level2Node, 2L, level2Name, nameToSyncId);
                         DkhCategorySub level2Sub = new DkhCategorySub();
                         level2Sub.setCustomerId(bo.getCustomerId());
                         level2Sub.setMainCategoryId(mainCategoryId);
@@ -419,16 +403,14 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
                         level2Sub.setLevel(2L);
                         level2Sub.setSortOrder(level2Node.has("sortOrder") ? level2Node.get("sortOrder").asLong() : 0L);
                         level2Sub.setStatus(level2Node.has("status") ? level2Node.get("status").asLong() : 1L);
-                        // 回填远程同步ID
-                        if (nameToSyncId != null && StringUtils.isNotBlank(level2Name)) {
-                            level2Sub.setSyncCategoryId(nameToSyncId.get("2:" + level2Name));
-                        }
+                        level2Sub.setSyncCategoryId(level2SyncId);
                         categorySubMapper.insert(level2Sub);
 
                         JsonNode level3Nodes = level2Node.get("children");
                         if (level3Nodes != null && level3Nodes.isArray() && !level3Nodes.isEmpty()) {
                             for (JsonNode level3Node : level3Nodes) {
                                 String level3Name = level3Node.has("name") ? level3Node.get("name").asText() : null;
+                                Long level3SyncId = getSyncCategoryIdFromNode(level3Node, 3L, level3Name, nameToSyncId);
                                 DkhCategorySub level3Sub = new DkhCategorySub();
                                 level3Sub.setCustomerId(bo.getCustomerId());
                                 level3Sub.setMainCategoryId(mainCategoryId);
@@ -437,10 +419,7 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
                                 level3Sub.setLevel(3L);
                                 level3Sub.setSortOrder(level3Node.has("sortOrder") ? level3Node.get("sortOrder").asLong() : 0L);
                                 level3Sub.setStatus(level3Node.has("status") ? level3Node.get("status").asLong() : 1L);
-                                // 回填远程同步ID
-                                if (nameToSyncId != null && StringUtils.isNotBlank(level3Name)) {
-                                    level3Sub.setSyncCategoryId(nameToSyncId.get("3:" + level3Name));
-                                }
+                                level3Sub.setSyncCategoryId(level3SyncId);
                                 categorySubMapper.insert(level3Sub);
                             }
                         }
@@ -452,6 +431,24 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
         }
     }
 
+    /**
+     * 从 JSON 节点获取 syncCategoryId:优先从节点字段读取,其次从远程名称映射查找
+     */
+    private Long getSyncCategoryIdFromNode(JsonNode node, Long classLevel, String name, Map<String, Long> nameToSyncId) {
+        // 优先从 JSON 中的 syncCategoryId 字段读取(已存在节点的真实远程ID)
+        if (node.has("syncCategoryId") && !node.get("syncCategoryId").isNull()) {
+            String syncIdStr = node.get("syncCategoryId").asText();
+            if (StringUtils.isNotBlank(syncIdStr)) {
+                return Long.valueOf(syncIdStr);
+            }
+        }
+        // 回退:新增节点从远程名称映射查找
+        if (nameToSyncId != null && StringUtils.isNotBlank(name)) {
+            return nameToSyncId.get(classLevel + ":" + name);
+        }
+        return null;
+    }
+
     /**
      * 从远程分类树构建名称→ID映射
      * key: "classLevel:categoryName" → value: remoteId
@@ -504,6 +501,9 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
                     // 注入 syncCategoryId
                     injectSyncCategoryId(vo.getId(), subMenus);
                     vo.setSubMenus(subMenus);
+                    // 回写到 panelConfigJson,使前端也能拿到 syncCategoryId
+                    config.put("subMenus", subMenus);
+                    vo.setPanelConfigJson(objectMapper.writeValueAsString(config));
                 }
 
                 // 构建 panelData(排除 subMenus,保留 mainTitle/subTitle/notes/groups)
@@ -567,7 +567,7 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
             if (StringUtils.isNotBlank(name)) {
                 Long syncId = nameToSyncId.get(currentLevel + ":" + name);
                 if (syncId != null) {
-                    node.put("syncCategoryId", syncId);
+                    node.put("syncCategoryId", String.valueOf(syncId));
                 }
             }
             // 递归处理子节点
@@ -581,6 +581,20 @@ public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMappe
         }
     }
 
+    /**
+     * 修改状态
+     *
+     * @param bo 包含 id 和 status
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateStatus(DkhCategoryMainBo bo) {
+        DkhCategoryMain entity = new DkhCategoryMain();
+        entity.setId(bo.getId());
+        entity.setStatus(bo.getStatus());
+        return baseMapper.updateById(entity) > 0;
+    }
+
     /**
      * 校验并批量删除分类设置主信息
      *

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysAnnouncement.java

@@ -47,7 +47,7 @@ public class SysAnnouncement extends TenantEntity {
     /**
      * 封面图片(OSS ID)
      */
-    private Long coverImage;
+    private String coverImage;
 
     /**
      * 是否显示(0否 1是)

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysAnnouncementBo.java

@@ -54,7 +54,7 @@ public class SysAnnouncementBo extends BaseEntity {
      * 封面图片(OSS ID)
      */
 //    @NotNull(message = "封面图片(OSS ID)不能为空", groups = { AddGroup.class, EditGroup.class })
-    private Long coverImage;
+    private String coverImage;
 
     /**
      * 是否显示(0否 1是)

+ 2 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysAnnouncementVo.java

@@ -60,12 +60,12 @@ public class SysAnnouncementVo implements Serializable {
      */
     @ExcelProperty(value = "封面图片", converter = ExcelDictConvert.class)
     @ExcelDictFormat(readConverterExp = "O=SS,I=D")
-    private Long coverImage;
+    private String coverImage;
 
     /**
      * 封面图片(OSS ID)Url
      */
-    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "coverImage")
+//    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "coverImage")
     private String coverImageUrl;
     /**
      * 是否显示(0否 1是)