|
@@ -4,10 +4,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
import org.dromara.common.core.utils.MapstructUtils;
|
|
import org.dromara.common.core.utils.MapstructUtils;
|
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
@@ -24,11 +26,16 @@ import org.dromara.mall.mapper.EpCategoryItemMapper;
|
|
|
import org.dromara.mall.mapper.EpCategoryMainMapper;
|
|
import org.dromara.mall.mapper.EpCategoryMainMapper;
|
|
|
import org.dromara.mall.service.IEpCategoryMainService;
|
|
import org.dromara.mall.service.IEpCategoryMainService;
|
|
|
import org.dromara.mall.service.IEpSearchConfigService;
|
|
import org.dromara.mall.service.IEpSearchConfigService;
|
|
|
|
|
+import org.dromara.product.api.RemoteCategoryService;
|
|
|
|
|
+import org.dromara.product.api.domain.CategoryDto;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.Collection;
|
|
import java.util.Collection;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 分类设置主Service业务层处理
|
|
* 分类设置主Service业务层处理
|
|
@@ -47,6 +54,9 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
|
|
|
|
|
private final IEpSearchConfigService searchConfigService;
|
|
private final IEpSearchConfigService searchConfigService;
|
|
|
|
|
|
|
|
|
|
+ @DubboReference
|
|
|
|
|
+ private RemoteCategoryService remoteCategoryService;
|
|
|
|
|
+
|
|
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -58,7 +68,7 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
@Override
|
|
@Override
|
|
|
public EpCategoryMainVo queryById(Long id) {
|
|
public EpCategoryMainVo queryById(Long id) {
|
|
|
// 查询主表数据
|
|
// 查询主表数据
|
|
|
- EpCategoryMainVo mainVo = baseMapper.selectVoById(id);
|
|
|
|
|
|
|
+ /* EpCategoryMainVo mainVo = baseMapper.selectVoById(id);
|
|
|
if (mainVo == null) {
|
|
if (mainVo == null) {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
@@ -111,11 +121,164 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
|
|
|
|
|
responseVo.setTags(tags);
|
|
responseVo.setTags(tags);
|
|
|
panelData.setNotes(notes);
|
|
panelData.setNotes(notes);
|
|
|
- }
|
|
|
|
|
|
|
+ }*/
|
|
|
EpCategoryMainVo vo = baseMapper.selectVoById(id);
|
|
EpCategoryMainVo vo = baseMapper.selectVoById(id);
|
|
|
|
|
+ if (vo == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有同步分类ID,查询分类树结构
|
|
|
|
|
+ if (vo.getSyncCategoryId() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ List<CategoryDto> categoryTree = remoteCategoryService.getCategoryTreeById(vo.getSyncCategoryId());
|
|
|
|
|
+
|
|
|
|
|
+ // 将分类树转换为 subMenus 格式
|
|
|
|
|
+ if (categoryTree != null && !categoryTree.isEmpty()) {
|
|
|
|
|
+ // 构建分类树结构
|
|
|
|
|
+ List<Map<String, Object>> subMenus = buildCategoryTree(categoryTree);
|
|
|
|
|
+
|
|
|
|
|
+ // 将 subMenus 设置到 vo 中
|
|
|
|
|
+ vo.setSubMenus(subMenus);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建 panelData(面板展示数据)
|
|
|
|
|
+ EpCategoryMainVo.PanelDataVo panelData = buildPanelData(vo, categoryTree);
|
|
|
|
|
+ vo.setPanelData(panelData);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("查询分类树失败", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return vo;
|
|
return vo;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建分类树结构(只返回二级及以后的分类,不包含一级分类)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param categories 扁平的分类列表
|
|
|
|
|
+ * @return 树形结构的 subMenus(二级分类列表)
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<Map<String, Object>> buildCategoryTree(List<CategoryDto> categories) {
|
|
|
|
|
+ if (categories == null || categories.isEmpty()) {
|
|
|
|
|
+ return new ArrayList<>();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("开始构建分类树 - 总分类数量: {}", categories.size());
|
|
|
|
|
+
|
|
|
|
|
+ // 按层级分组
|
|
|
|
|
+ Map<Long, List<CategoryDto>> levelMap = new HashMap<>();
|
|
|
|
|
+ for (CategoryDto category : categories) {
|
|
|
|
|
+ Long level = category.getClassLevel();
|
|
|
|
|
+ if (level != null) {
|
|
|
|
|
+ levelMap.computeIfAbsent(level, k -> new ArrayList<>()).add(category);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("按层级分组 - levelMap: {}", levelMap.keySet());
|
|
|
|
|
+
|
|
|
|
|
+ // 获取一级分类(用于查找其子分类)
|
|
|
|
|
+ List<CategoryDto> level1Categories = levelMap.getOrDefault(1L, new ArrayList<>());
|
|
|
|
|
+ log.info("一级分类数量: {}, IDs: {}", level1Categories.size(), level1Categories.stream().map(CategoryDto::getId).collect(Collectors.toList()));
|
|
|
|
|
+
|
|
|
|
|
+ // 获取二级分类(作为 subMenus 的根节点)
|
|
|
|
|
+ List<CategoryDto> level2Categories = levelMap.getOrDefault(2L, new ArrayList<>());
|
|
|
|
|
+ log.info("二级分类数量: {}", level2Categories.size());
|
|
|
|
|
+
|
|
|
|
|
+ List<Map<String, Object>> subMenus = new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ for (CategoryDto level2 : level2Categories) {
|
|
|
|
|
+ Map<String, Object> level2Map = new HashMap<>();
|
|
|
|
|
+ level2Map.put("id", level2.getId());
|
|
|
|
|
+ level2Map.put("name", level2.getCategoryName());
|
|
|
|
|
+ level2Map.put("sortOrder", level2.getSort());
|
|
|
|
|
+ level2Map.put("status", level2.getIsShow());
|
|
|
|
|
+ level2Map.put("level", level2.getClassLevel());
|
|
|
|
|
+
|
|
|
|
|
+ // 查找三级分类
|
|
|
|
|
+ List<CategoryDto> level3Categories = categories.stream()
|
|
|
|
|
+ .filter(c -> c.getParentId() != null && c.getParentId().equals(level2.getId()))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ log.info("二级分类 [{}] 的三级分类数量: {}", level2.getCategoryName(), level3Categories.size());
|
|
|
|
|
+
|
|
|
|
|
+ List<Map<String, Object>> children = new ArrayList<>();
|
|
|
|
|
+ for (CategoryDto level3 : level3Categories) {
|
|
|
|
|
+ Map<String, Object> level3Map = new HashMap<>();
|
|
|
|
|
+ level3Map.put("id", level3.getId());
|
|
|
|
|
+ level3Map.put("name", level3.getCategoryName());
|
|
|
|
|
+ level3Map.put("sortOrder", level3.getSort());
|
|
|
|
|
+ level3Map.put("status", level3.getIsShow());
|
|
|
|
|
+ level3Map.put("level", level3.getClassLevel());
|
|
|
|
|
+ children.add(level3Map);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ level2Map.put("children", children);
|
|
|
|
|
+ subMenus.add(level2Map);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("构建完成 - subMenus 数量: {}", subMenus.size());
|
|
|
|
|
+ return subMenus;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建面板数据(panelData)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param vo 分类主表 VO
|
|
|
|
|
+ * @param categories 分类树列表
|
|
|
|
|
+ * @return PanelDataVo
|
|
|
|
|
+ */
|
|
|
|
|
+ private EpCategoryMainVo.PanelDataVo buildPanelData(EpCategoryMainVo vo, List<CategoryDto> categories) {
|
|
|
|
|
+ EpCategoryMainVo.PanelDataVo panelData = new EpCategoryMainVo.PanelDataVo();
|
|
|
|
|
+
|
|
|
|
|
+ // 设置主标题和副标题
|
|
|
|
|
+ panelData.setMainTitle(vo.getPanelMainTitle());
|
|
|
|
|
+ panelData.setSubTitle(vo.getPanelSubTitle());
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库中查询 notes 标签项
|
|
|
|
|
+ List<EpCategoryMainVo.NoteItem> notes = new ArrayList<>();
|
|
|
|
|
+ if (vo.getNotes() != null) {
|
|
|
|
|
+ for (EpCategoryItemVo itemVo : vo.getNotes()) {
|
|
|
|
|
+ EpCategoryMainVo.NoteItem noteItem = new EpCategoryMainVo.NoteItem();
|
|
|
|
|
+ noteItem.setName(itemVo.getName());
|
|
|
|
|
+ noteItem.setLink(itemVo.getLink());
|
|
|
|
|
+ notes.add(noteItem);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ panelData.setNotes(notes);
|
|
|
|
|
+
|
|
|
|
|
+ // 从分类树中构建 groups(二级分类作为分组标题,三级分类作为 items)
|
|
|
|
|
+ List<EpCategoryMainVo.GroupItem> groups = new ArrayList<>();
|
|
|
|
|
+ if (categories != null && !categories.isEmpty()) {
|
|
|
|
|
+ // 按层级分组
|
|
|
|
|
+ Map<Long, List<CategoryDto>> levelMap = new HashMap<>();
|
|
|
|
|
+ for (CategoryDto category : categories) {
|
|
|
|
|
+ Long level = category.getClassLevel();
|
|
|
|
|
+ if (level != null) {
|
|
|
|
|
+ levelMap.computeIfAbsent(level, k -> new ArrayList<>()).add(category);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取二级分类作为分组
|
|
|
|
|
+ List<CategoryDto> level2Categories = levelMap.getOrDefault(2L, new ArrayList<>());
|
|
|
|
|
+ for (CategoryDto level2 : level2Categories) {
|
|
|
|
|
+ EpCategoryMainVo.GroupItem group = new EpCategoryMainVo.GroupItem();
|
|
|
|
|
+ group.setTitle(level2.getCategoryName());
|
|
|
|
|
+
|
|
|
|
|
+ // 获取该二级分类下的所有三级分类名称
|
|
|
|
|
+ List<String> items = categories.stream()
|
|
|
|
|
+ .filter(c -> c.getParentId() != null && c.getParentId().equals(level2.getId()))
|
|
|
|
|
+ .map(CategoryDto::getCategoryName)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ group.setItems(items);
|
|
|
|
|
+ groups.add(group);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ panelData.setGroups(groups);
|
|
|
|
|
+
|
|
|
|
|
+ return panelData;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 分页查询分类设置主列表
|
|
* 分页查询分类设置主列表
|
|
@@ -130,12 +293,32 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
Page<EpCategoryMainVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
Page<EpCategoryMainVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
|
List<EpCategoryMainVo> records = result.getRecords();
|
|
List<EpCategoryMainVo> records = result.getRecords();
|
|
|
EpSearchConfigVo currentSearchConfig = searchConfigService.getCurrentSearchConfig();
|
|
EpSearchConfigVo currentSearchConfig = searchConfigService.getCurrentSearchConfig();
|
|
|
- // 为每个分类填充对应的标签项
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 为每个分类填充对应的标签项和分类树
|
|
|
for (EpCategoryMainVo record : records) {
|
|
for (EpCategoryMainVo record : records) {
|
|
|
fillCategoryItems(record);
|
|
fillCategoryItems(record);
|
|
|
- if (null!=currentSearchConfig){
|
|
|
|
|
|
|
+ if (null != currentSearchConfig) {
|
|
|
record.setCategoryThemeColor(currentSearchConfig.getCategoryThemeColor());
|
|
record.setCategoryThemeColor(currentSearchConfig.getCategoryThemeColor());
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有同步分类ID,查询分类树结构
|
|
|
|
|
+ if (record.getSyncCategoryId() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ List<CategoryDto> categoryTree = remoteCategoryService.getCategoryTreeById(record.getSyncCategoryId());
|
|
|
|
|
+
|
|
|
|
|
+ // 将分类树转换为 subMenus 格式
|
|
|
|
|
+ if (categoryTree != null && !categoryTree.isEmpty()) {
|
|
|
|
|
+ List<Map<String, Object>> subMenus = buildCategoryTree(categoryTree);
|
|
|
|
|
+ record.setSubMenus(subMenus);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建 panelData(面板展示数据)
|
|
|
|
|
+ EpCategoryMainVo.PanelDataVo panelData = buildPanelData(record, categoryTree);
|
|
|
|
|
+ record.setPanelData(panelData);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("查询分类树失败, categoryId: {}", record.getSyncCategoryId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return TableDataInfo.build(result);
|
|
return TableDataInfo.build(result);
|
|
@@ -150,7 +333,30 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
@Override
|
|
@Override
|
|
|
public List<EpCategoryMainVo> queryList(EpCategoryMainBo bo) {
|
|
public List<EpCategoryMainVo> queryList(EpCategoryMainBo bo) {
|
|
|
LambdaQueryWrapper<EpCategoryMain> lqw = buildQueryWrapper(bo);
|
|
LambdaQueryWrapper<EpCategoryMain> lqw = buildQueryWrapper(bo);
|
|
|
- return baseMapper.selectVoList(lqw);
|
|
|
|
|
|
|
+ List<EpCategoryMainVo> voList = baseMapper.selectVoList(lqw);
|
|
|
|
|
+
|
|
|
|
|
+ // 为每个分类填充分类树和 panelData
|
|
|
|
|
+ for (EpCategoryMainVo vo : voList) {
|
|
|
|
|
+ if (vo.getSyncCategoryId() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ List<CategoryDto> categoryTree = remoteCategoryService.getCategoryTreeById(vo.getSyncCategoryId());
|
|
|
|
|
+
|
|
|
|
|
+ if (categoryTree != null && !categoryTree.isEmpty()) {
|
|
|
|
|
+ // 构建 subMenus(二级及以后的分类)
|
|
|
|
|
+ List<Map<String, Object>> subMenus = buildCategoryTree(categoryTree);
|
|
|
|
|
+ vo.setSubMenus(subMenus);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建 panelData(面板展示数据)
|
|
|
|
|
+ EpCategoryMainVo.PanelDataVo panelData = buildPanelData(vo, categoryTree);
|
|
|
|
|
+ vo.setPanelData(panelData);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("查询分类树失败, categoryId: {}", vo.getSyncCategoryId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return voList;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private LambdaQueryWrapper<EpCategoryMain> buildQueryWrapper(EpCategoryMainBo bo) {
|
|
private LambdaQueryWrapper<EpCategoryMain> buildQueryWrapper(EpCategoryMainBo bo) {
|
|
@@ -178,14 +384,129 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
public Boolean insertByBo(EpCategoryMainBo bo) {
|
|
public Boolean insertByBo(EpCategoryMainBo bo) {
|
|
|
EpCategoryMain add = MapstructUtils.convert(bo, EpCategoryMain.class);
|
|
EpCategoryMain add = MapstructUtils.convert(bo, EpCategoryMain.class);
|
|
|
validEntityBeforeSave(add);
|
|
validEntityBeforeSave(add);
|
|
|
|
|
+
|
|
|
|
|
+ // 先插入主表数据
|
|
|
boolean flag = baseMapper.insert(add) > 0;
|
|
boolean flag = baseMapper.insert(add) > 0;
|
|
|
- if (flag) {
|
|
|
|
|
- bo.setId(add.getId());
|
|
|
|
|
|
|
+ if (!flag) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 保存分类项列表
|
|
|
|
|
- saveCategoryItems(add.getId(), bo);
|
|
|
|
|
|
|
+ // 解析 remark 中的 subMenus 并同步到分类表
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (StringUtils.isNotBlank(bo.getRemark())) {
|
|
|
|
|
+ JsonNode rootNode = objectMapper.readTree(bo.getRemark());
|
|
|
|
|
+ JsonNode subMenus = rootNode.get("subMenus");
|
|
|
|
|
+
|
|
|
|
|
+ if (subMenus != null && subMenus.isArray()) {
|
|
|
|
|
+ // 使用 bo.name 创建一级分类
|
|
|
|
|
+ CategoryDto level1Dto = new CategoryDto();
|
|
|
|
|
+ level1Dto.setCategoryName(bo.getName()); // 使用 bo.name 作为一级分类名称
|
|
|
|
|
+ level1Dto.setParentId(0L); // 一级分类的父ID为0
|
|
|
|
|
+ level1Dto.setClassLevel(1L); // 一级分类层级为1
|
|
|
|
|
+ level1Dto.setIsShow(1L); // 默认显示
|
|
|
|
|
+ level1Dto.setSort(bo.getSortOrder() != null ? bo.getSortOrder() : 0L);
|
|
|
|
|
+ level1Dto.setDataSource("youyi"); // 数据来源设置为 youyi
|
|
|
|
|
+ level1Dto.setPlatform(3L); // 平台设置为 3(企业购)
|
|
|
|
|
+ level1Dto.setAncestors("0"); // 一级分类的祖籍为0
|
|
|
|
|
+
|
|
|
|
|
+ // 插入一级分类
|
|
|
|
|
+ List<CategoryDto> level1List = new ArrayList<>();
|
|
|
|
|
+ level1List.add(level1Dto);
|
|
|
|
|
+ Long level1Id = remoteCategoryService.insertCategory(level1List);
|
|
|
|
|
+
|
|
|
|
|
+ if (level1Id != null) {
|
|
|
|
|
+ // 将一级分类的 ID 绑定到 add.syncCategoryId
|
|
|
|
|
+ add.setSyncCategoryId(level1Id);
|
|
|
|
|
+ baseMapper.updateById(add);
|
|
|
|
|
+
|
|
|
|
|
+ String level1Ancestors = "0," + level1Id;
|
|
|
|
|
+
|
|
|
|
|
+ // 处理 subMenus 作为二级分类
|
|
|
|
|
+ if (subMenus.size() > 0) {
|
|
|
|
|
+ List<Long> level2Ids = new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ for (JsonNode level2Node : subMenus) {
|
|
|
|
|
+ CategoryDto level2Dto = new CategoryDto();
|
|
|
|
|
+ level2Dto.setCategoryName(level2Node.has("name") ? level2Node.get("name").asText() : null);
|
|
|
|
|
+ level2Dto.setParentId(level1Id); // 二级分类的父ID为一级分类ID
|
|
|
|
|
+ level2Dto.setClassLevel(2L); // 二级分类层级为2
|
|
|
|
|
+ level2Dto.setIsShow(level2Node.has("status") ? level2Node.get("status").asLong() : 1L);
|
|
|
|
|
+ level2Dto.setSort(level2Node.has("sortOrder") ? level2Node.get("sortOrder").asLong() : 0L);
|
|
|
|
|
+ level2Dto.setDataSource("youyi");
|
|
|
|
|
+ level2Dto.setPlatform(3L); // 平台设置为 3(企业购)
|
|
|
|
|
+ level2Dto.setAncestors(level1Ancestors); // 二级分类的祖籍为 0,一级ID
|
|
|
|
|
+
|
|
|
|
|
+ // 逐个插入二级分类以获取 ID
|
|
|
|
|
+ List<CategoryDto> level2List = new ArrayList<>();
|
|
|
|
|
+ level2List.add(level2Dto);
|
|
|
|
|
+ Long level2Id = remoteCategoryService.insertCategory(level2List);
|
|
|
|
|
+ if (level2Id != null) {
|
|
|
|
|
+ level2Ids.add(level2Id);
|
|
|
|
|
+
|
|
|
|
|
+ // 处理三级分类(当前二级分类的 children)
|
|
|
|
|
+ JsonNode level3Nodes = level2Node.get("children");
|
|
|
|
|
+ if (level3Nodes != null && level3Nodes.isArray() && !level3Nodes.isEmpty()) {
|
|
|
|
|
+ String level2Ancestors = level1Ancestors + "," + level2Id;
|
|
|
|
|
+
|
|
|
|
|
+ for (JsonNode level3Node : level3Nodes) {
|
|
|
|
|
+ CategoryDto level3Dto = new CategoryDto();
|
|
|
|
|
+ level3Dto.setCategoryName(level3Node.has("name") ? level3Node.get("name").asText() : null);
|
|
|
|
|
+ level3Dto.setParentId(level2Id); // 三级分类的父ID为二级分类ID
|
|
|
|
|
+ level3Dto.setClassLevel(3L); // 三级分类层级为3
|
|
|
|
|
+ level3Dto.setIsShow(level3Node.has("status") ? level3Node.get("status").asLong() : 1L);
|
|
|
|
|
+ level3Dto.setSort(level3Node.has("sortOrder") ? level3Node.get("sortOrder").asLong() : 0L);
|
|
|
|
|
+ level3Dto.setDataSource("youyi");
|
|
|
|
|
+ level3Dto.setPlatform(3L); // 平台设置为 3(企业购)
|
|
|
|
|
+ level3Dto.setAncestors(level2Ancestors); // 三级分类的祖籍为 0,一级ID,二级ID
|
|
|
|
|
+
|
|
|
|
|
+ // 逐个插入三级分类
|
|
|
|
|
+ List<CategoryDto> level3List = new ArrayList<>();
|
|
|
|
|
+ level3List.add(level3Dto);
|
|
|
|
|
+ remoteCategoryService.insertCategory(level3List);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
|
+ log.error("解析 remark JSON 数据失败", e);
|
|
|
|
|
+ throw new RuntimeException("解析分类数据失败", e);
|
|
|
}
|
|
}
|
|
|
- return flag;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ bo.setId(add.getId());
|
|
|
|
|
+
|
|
|
|
|
+ // 保存分类项列表
|
|
|
|
|
+ saveCategoryItems(add.getId(), bo);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 批量插入分类并返回 ID 列表
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param categoryDtos 分类 DTO 列表
|
|
|
|
|
+ * @return 插入后的 ID 列表
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<Long> batchInsertCategories(List<CategoryDto> categoryDtos) {
|
|
|
|
|
+ if (categoryDtos == null || categoryDtos.isEmpty()) {
|
|
|
|
|
+ return new ArrayList<>();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 调用远程服务批量插入(会回填 ID 到 DTO 中)
|
|
|
|
|
+ remoteCategoryService.insertCategory(categoryDtos);
|
|
|
|
|
+
|
|
|
|
|
+ // 从 DTO 中收集 ID
|
|
|
|
|
+ List<Long> ids = new ArrayList<>();
|
|
|
|
|
+ for (CategoryDto dto : categoryDtos) {
|
|
|
|
|
+ if (dto.getId() != null) {
|
|
|
|
|
+ ids.add(dto.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ids;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -198,16 +519,127 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
public Boolean updateByBo(EpCategoryMainBo bo) {
|
|
public Boolean updateByBo(EpCategoryMainBo bo) {
|
|
|
EpCategoryMain update = MapstructUtils.convert(bo, EpCategoryMain.class);
|
|
EpCategoryMain update = MapstructUtils.convert(bo, EpCategoryMain.class);
|
|
|
validEntityBeforeSave(update);
|
|
validEntityBeforeSave(update);
|
|
|
|
|
+
|
|
|
|
|
+ // 先更新主表数据
|
|
|
boolean flag = baseMapper.updateById(update) > 0;
|
|
boolean flag = baseMapper.updateById(update) > 0;
|
|
|
if (flag) {
|
|
if (flag) {
|
|
|
- // 先根据categoryId删除原有的子项
|
|
|
|
|
|
|
+ // 处理分类树的增量更新
|
|
|
|
|
+ if (bo.getSyncCategoryId() != null && StringUtils.isNotBlank(bo.getRemark())) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ JsonNode rootNode = objectMapper.readTree(bo.getRemark());
|
|
|
|
|
+ JsonNode subMenus = rootNode.get("subMenus");
|
|
|
|
|
+
|
|
|
|
|
+ if (subMenus != null && subMenus.isArray()) {
|
|
|
|
|
+ // 构建新的分类树数据
|
|
|
|
|
+ List<CategoryDto> newCategoryTree = buildCategoryTreeFromSubMenus(
|
|
|
|
|
+ bo.getName(),
|
|
|
|
|
+ subMenus,
|
|
|
|
|
+ bo.getSyncCategoryId()
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 调用远程服务进行增量更新
|
|
|
|
|
+ remoteCategoryService.updateCategoryTree(bo.getSyncCategoryId(), newCategoryTree);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("更新分类树失败", e);
|
|
|
|
|
+ // 分类树更新失败不影响主表更新,只记录日志
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理标签项(tags/notes)- 这部分可以删除重建
|
|
|
categoryItemMapper.delete(Wrappers.<EpCategoryItem>lambdaQuery().eq(EpCategoryItem::getCategoryId, update.getId()));
|
|
categoryItemMapper.delete(Wrappers.<EpCategoryItem>lambdaQuery().eq(EpCategoryItem::getCategoryId, update.getId()));
|
|
|
-
|
|
|
|
|
- // 再重新添加新的子项
|
|
|
|
|
saveCategoryItems(update.getId(), bo);
|
|
saveCategoryItems(update.getId(), bo);
|
|
|
}
|
|
}
|
|
|
return flag;
|
|
return flag;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从 subMenus 构建分类树 DTO 列表(树形结构)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param categoryName 一级分类名称
|
|
|
|
|
+ * @param subMenus 子菜单 JSON 节点
|
|
|
|
|
+ * @param rootCategoryId 根分类ID
|
|
|
|
|
+ * @return 分类树 DTO 列表(只包含一级分类,带 children)
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<CategoryDto> buildCategoryTreeFromSubMenus(String categoryName, JsonNode subMenus, Long rootCategoryId) {
|
|
|
|
|
+ List<CategoryDto> result = new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ // 添加一级分类(根分类)
|
|
|
|
|
+ CategoryDto rootDto = new CategoryDto();
|
|
|
|
|
+ rootDto.setId(rootCategoryId); // 使用现有的 ID
|
|
|
|
|
+ rootDto.setCategoryName(categoryName);
|
|
|
|
|
+ rootDto.setParentId(0L);
|
|
|
|
|
+ rootDto.setClassLevel(1L);
|
|
|
|
|
+ rootDto.setDataSource("youyi");
|
|
|
|
|
+ rootDto.setPlatform(3L);
|
|
|
|
|
+
|
|
|
|
|
+ // 处理二级分类
|
|
|
|
|
+ List<CategoryDto> level2Children = new ArrayList<>();
|
|
|
|
|
+ if (subMenus != null && subMenus.isArray()) {
|
|
|
|
|
+ for (JsonNode level2Node : subMenus) {
|
|
|
|
|
+ // 如果前端传来的数据包含 level=1 的一级分类,需要跳过(因为已经在 bo.name 中)
|
|
|
|
|
+ if (level2Node.has("level") && level2Node.get("level").asInt() == 1) {
|
|
|
|
|
+ // 这是错误的数据结构,应该直接使用 bo.name 作为一级分类
|
|
|
|
|
+ // 递归处理这个一级分类的 children 作为二级分类
|
|
|
|
|
+ JsonNode nestedChildren = level2Node.get("children");
|
|
|
|
|
+ if (nestedChildren != null && nestedChildren.isArray()) {
|
|
|
|
|
+ for (JsonNode nestedChild : nestedChildren) {
|
|
|
|
|
+ CategoryDto level2Dto = buildCategoryDtoFromNode(nestedChild, rootCategoryId, 2L);
|
|
|
|
|
+ level2Children.add(level2Dto);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ continue; // 跳过一级分类节点
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 正常的二级分类
|
|
|
|
|
+ CategoryDto level2Dto = buildCategoryDtoFromNode(level2Node, rootCategoryId, 2L);
|
|
|
|
|
+ level2Children.add(level2Dto);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rootDto.setChildren(level2Children);
|
|
|
|
|
+ result.add(rootDto);
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从 JSON 节点构建 CategoryDto
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param node JSON 节点
|
|
|
|
|
+ * @param parentId 父分类ID
|
|
|
|
|
+ * @param classLevel 分类层级
|
|
|
|
|
+ * @return CategoryDto
|
|
|
|
|
+ */
|
|
|
|
|
+ private CategoryDto buildCategoryDtoFromNode(JsonNode node, Long parentId, Long classLevel) {
|
|
|
|
|
+ CategoryDto dto = new CategoryDto();
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有 ID,说明是已存在的分类
|
|
|
|
|
+ if (node.has("id") && node.get("id").asLong() > 0) {
|
|
|
|
|
+ dto.setId(node.get("id").asLong());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ dto.setCategoryName(node.has("name") ? node.get("name").asText() : null);
|
|
|
|
|
+ dto.setParentId(parentId);
|
|
|
|
|
+ dto.setClassLevel(classLevel);
|
|
|
|
|
+ dto.setIsShow(node.has("status") ? node.get("status").asLong() : 1L);
|
|
|
|
|
+ dto.setSort(node.has("sortOrder") ? node.get("sortOrder").asLong() : 0L);
|
|
|
|
|
+ dto.setDataSource("youyi");
|
|
|
|
|
+ dto.setPlatform(3L);
|
|
|
|
|
+
|
|
|
|
|
+ // 递归处理子分类
|
|
|
|
|
+ JsonNode childrenNode = node.get("children");
|
|
|
|
|
+ if (childrenNode != null && childrenNode.isArray() && !childrenNode.isEmpty()) {
|
|
|
|
|
+ List<CategoryDto> children = new ArrayList<>();
|
|
|
|
|
+ for (JsonNode childNode : childrenNode) {
|
|
|
|
|
+ CategoryDto childDto = buildCategoryDtoFromNode(childNode, dto.getId() != null ? dto.getId() : parentId, classLevel + 1);
|
|
|
|
|
+ children.add(childDto);
|
|
|
|
|
+ }
|
|
|
|
|
+ dto.setChildren(children);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return dto;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 保存分类项(从 remark 和 categoryItemList 中解析)
|
|
* 保存分类项(从 remark 和 categoryItemList 中解析)
|
|
@@ -254,20 +686,8 @@ public class EpCategoryMainServiceImpl extends ServiceImpl<EpCategoryMainMapper,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 处理 groups(如果需要)
|
|
|
|
|
- JsonNode groupsNode = rootNode.get("groups");
|
|
|
|
|
- if (groupsNode != null && groupsNode.isArray()) {
|
|
|
|
|
- int sortOrder = items.size();
|
|
|
|
|
- for (JsonNode groupNode : groupsNode) {
|
|
|
|
|
- EpCategoryItem item = new EpCategoryItem();
|
|
|
|
|
- item.setCategoryId(categoryId);
|
|
|
|
|
- item.setItemType("group");
|
|
|
|
|
- item.setName(groupNode.has("name") ? groupNode.get("name").asText() : null);
|
|
|
|
|
- item.setLink(groupNode.has("link") ? groupNode.get("link").asText() : null);
|
|
|
|
|
- item.setSortOrder((long) sortOrder++);
|
|
|
|
|
- items.add(item);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 注意:groups 数据是从分类树动态生成的,不需要保存到 ep_category_item 表
|
|
|
|
|
+ // 所以这里不处理 groups 节点
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("解析 remark JSON 数据失败", e);
|
|
log.error("解析 remark JSON 数据失败", e);
|
|
|
}
|
|
}
|