|
|
@@ -0,0 +1,598 @@
|
|
|
+package org.dromara.mall.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+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.ObjectUtils;
|
|
|
+import org.dromara.common.core.utils.StringUtils;
|
|
|
+import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
+import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
+import org.dromara.mall.domain.DkhCategoryMain;
|
|
|
+import org.dromara.mall.domain.DkhCategorySub;
|
|
|
+import org.dromara.mall.domain.bo.DkhCategoryMainBo;
|
|
|
+import org.dromara.mall.domain.vo.DkhCategoryMainVo;
|
|
|
+import org.dromara.mall.domain.vo.DkhMallConfigVo;
|
|
|
+import org.dromara.mall.domain.vo.EpSearchConfigVo;
|
|
|
+import org.dromara.mall.mapper.DkhCategoryMainMapper;
|
|
|
+import org.dromara.mall.mapper.DkhCategorySubMapper;
|
|
|
+import org.dromara.mall.service.IDkhCategoryMainService;
|
|
|
+import org.dromara.mall.service.IDkhMallConfigService;
|
|
|
+import org.dromara.product.api.RemoteCategoryService;
|
|
|
+import org.dromara.product.api.domain.CategoryDto;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 分类设置主Service业务层处理
|
|
|
+ *
|
|
|
+ * @author LionLi
|
|
|
+ * @date 2026-06-02
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RequiredArgsConstructor
|
|
|
+@Service
|
|
|
+public class DkhCategoryMainServiceImpl extends ServiceImpl<DkhCategoryMainMapper, DkhCategoryMain> implements IDkhCategoryMainService {
|
|
|
+
|
|
|
+ private final DkhCategoryMainMapper baseMapper;
|
|
|
+
|
|
|
+ private final DkhCategorySubMapper categorySubMapper;
|
|
|
+
|
|
|
+ private final IDkhMallConfigService dkhMallConfigService;
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private RemoteCategoryService remoteCategoryService;
|
|
|
+
|
|
|
+ private static final ObjectMapper objectMapper = new ObjectMapper();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询分类设置主
|
|
|
+ *
|
|
|
+ * @param id 主键
|
|
|
+ * @return 分类设置主
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public DkhCategoryMainVo queryById(Long id) {
|
|
|
+ DkhCategoryMainVo vo = baseMapper.selectVoById(id);
|
|
|
+ if (vo != null) {
|
|
|
+ fillParsedFields(vo);
|
|
|
+ }
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页查询分类设置主列表
|
|
|
+ *
|
|
|
+ * @param bo 查询条件
|
|
|
+ * @param pageQuery 分页参数
|
|
|
+ * @return 分类设置主分页列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public TableDataInfo<DkhCategoryMainVo> queryPageList(DkhCategoryMainBo bo, PageQuery pageQuery) {
|
|
|
+ LambdaQueryWrapper<DkhCategoryMain> lqw = buildQueryWrapper(bo);
|
|
|
+ Page<DkhCategoryMainVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
|
+ DkhMallConfigVo currentMallConfig =null;
|
|
|
+ if (ObjectUtils.isNotEmpty(bo.getCustomerId())){
|
|
|
+ currentMallConfig= dkhMallConfigService.getCurrentMallConfig(bo.getCustomerId());
|
|
|
+ }
|
|
|
+
|
|
|
+ for (DkhCategoryMainVo vo : result.getRecords()) {
|
|
|
+ fillParsedFields(vo);
|
|
|
+ if (ObjectUtils.isNotEmpty(currentMallConfig)){
|
|
|
+ vo.setCategoryThemeColor(currentMallConfig.getCategoryThemeColor());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return TableDataInfo.build(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询符合条件的分类设置主列表
|
|
|
+ *
|
|
|
+ * @param bo 查询条件
|
|
|
+ * @return 分类设置主列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<DkhCategoryMainVo> queryList(DkhCategoryMainBo bo) {
|
|
|
+ LambdaQueryWrapper<DkhCategoryMain> lqw = buildQueryWrapper(bo);
|
|
|
+ List<DkhCategoryMainVo> list = baseMapper.selectVoList(lqw);
|
|
|
+ for (DkhCategoryMainVo vo : list) {
|
|
|
+ fillParsedFields(vo);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ private LambdaQueryWrapper<DkhCategoryMain> buildQueryWrapper(DkhCategoryMainBo bo) {
|
|
|
+ Map<String, Object> params = bo.getParams();
|
|
|
+ LambdaQueryWrapper<DkhCategoryMain> lqw = Wrappers.lambdaQuery();
|
|
|
+ lqw.orderByAsc(DkhCategoryMain::getId);
|
|
|
+ lqw.eq(bo.getCustomerId() != null, DkhCategoryMain::getCustomerId, bo.getCustomerId());
|
|
|
+ lqw.like(StringUtils.isNotBlank(bo.getName()), DkhCategoryMain::getName, bo.getName());
|
|
|
+ lqw.eq(StringUtils.isNotBlank(bo.getTagsJson()), DkhCategoryMain::getTagsJson, bo.getTagsJson());
|
|
|
+ lqw.eq(bo.getStatus() != null, DkhCategoryMain::getStatus, bo.getStatus());
|
|
|
+ lqw.eq(StringUtils.isNotBlank(bo.getPanelConfigJson()), DkhCategoryMain::getPanelConfigJson, bo.getPanelConfigJson());
|
|
|
+ lqw.eq(bo.getSyncCategoryId() != null, DkhCategoryMain::getSyncCategoryId, bo.getSyncCategoryId());
|
|
|
+ lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), DkhCategoryMain::getPlatformCode, bo.getPlatformCode());
|
|
|
+ return lqw;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增分类设置主
|
|
|
+ *
|
|
|
+ * @param bo 分类设置主
|
|
|
+ * @return 是否新增成功
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Boolean insertByBo(DkhCategoryMainBo bo) {
|
|
|
+ DkhCategoryMain add = MapstructUtils.convert(bo, DkhCategoryMain.class);
|
|
|
+ validEntityBeforeSave(add);
|
|
|
+
|
|
|
+ // 先插入主表数据
|
|
|
+ boolean flag = baseMapper.insert(add) > 0;
|
|
|
+ if (!flag) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析 panelConfigJson 中的 subMenus,同步到远程商品分类表 + 本地 sub 表
|
|
|
+ try {
|
|
|
+ if (StringUtils.isNotBlank(bo.getPanelConfigJson())) {
|
|
|
+ JsonNode rootNode = objectMapper.readTree(bo.getPanelConfigJson());
|
|
|
+ JsonNode subMenus = rootNode.get("subMenus");
|
|
|
+
|
|
|
+ if (subMenus != null && subMenus.isArray()) {
|
|
|
+ // ========== 1. 同步到远程商品分类表 ==========
|
|
|
+ CategoryDto level1Dto = new CategoryDto();
|
|
|
+ level1Dto.setCategoryName(bo.getName());
|
|
|
+ level1Dto.setParentId(0L);
|
|
|
+ level1Dto.setClassLevel(1L);
|
|
|
+ level1Dto.setIsShow(1L);
|
|
|
+ level1Dto.setSort(0L);
|
|
|
+ level1Dto.setDataSource("youyi");
|
|
|
+ level1Dto.setPlatform(4L);
|
|
|
+ level1Dto.setAncestors("0");
|
|
|
+
|
|
|
+ List<CategoryDto> level1List = new ArrayList<>();
|
|
|
+ level1List.add(level1Dto);
|
|
|
+ Long level1Id = remoteCategoryService.insertCategory(level1List);
|
|
|
+
|
|
|
+ if (level1Id != null) {
|
|
|
+ add.setSyncCategoryId(level1Id);
|
|
|
+ baseMapper.updateById(add);
|
|
|
+
|
|
|
+ String level1Ancestors = "0," + level1Id;
|
|
|
+
|
|
|
+ if (subMenus.size() > 0) {
|
|
|
+ for (JsonNode level2Node : subMenus) {
|
|
|
+ // 远程:二级分类
|
|
|
+ CategoryDto level2Dto = new CategoryDto();
|
|
|
+ level2Dto.setCategoryName(level2Node.has("name") ? level2Node.get("name").asText() : null);
|
|
|
+ level2Dto.setParentId(level1Id);
|
|
|
+ level2Dto.setClassLevel(2L);
|
|
|
+ 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(4L);
|
|
|
+ level2Dto.setAncestors(level1Ancestors);
|
|
|
+
|
|
|
+ List<CategoryDto> level2List = new ArrayList<>();
|
|
|
+ level2List.add(level2Dto);
|
|
|
+ Long level2Id = remoteCategoryService.insertCategory(level2List);
|
|
|
+
|
|
|
+ // ========== 2. 保存二级分类到本地 DkhCategorySub ==========
|
|
|
+ DkhCategorySub level2Sub = new DkhCategorySub();
|
|
|
+ level2Sub.setCustomerId(bo.getCustomerId());
|
|
|
+ level2Sub.setMainCategoryId(add.getId());
|
|
|
+ level2Sub.setParentId(0L);
|
|
|
+ level2Sub.setName(level2Node.has("name") ? level2Node.get("name").asText() : null);
|
|
|
+ level2Sub.setLevel(2L);
|
|
|
+ level2Sub.setSortOrder(level2Node.has("sortOrder") ? level2Node.get("sortOrder").asLong() : 0L);
|
|
|
+ level2Sub.setStatus(level2Node.has("status") ? level2Node.get("status").asLong() : 1L);
|
|
|
+ level2Sub.setSyncCategoryId(level2Id);
|
|
|
+ categorySubMapper.insert(level2Sub);
|
|
|
+
|
|
|
+ // 处理三级分类
|
|
|
+ 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);
|
|
|
+ level3Dto.setClassLevel(3L);
|
|
|
+ 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(4L);
|
|
|
+ level3Dto.setAncestors(level2Ancestors);
|
|
|
+
|
|
|
+ List<CategoryDto> level3List = new ArrayList<>();
|
|
|
+ level3List.add(level3Dto);
|
|
|
+ Long level3Id = remoteCategoryService.insertCategory(level3List);
|
|
|
+
|
|
|
+ // 本地:三级分类 → DkhCategorySub
|
|
|
+ DkhCategorySub level3Sub = new DkhCategorySub();
|
|
|
+ level3Sub.setCustomerId(bo.getCustomerId());
|
|
|
+ level3Sub.setMainCategoryId(add.getId());
|
|
|
+ level3Sub.setParentId(level2Sub.getId());
|
|
|
+ level3Sub.setName(level3Node.has("name") ? level3Node.get("name").asText() : null);
|
|
|
+ level3Sub.setLevel(3L);
|
|
|
+ level3Sub.setSortOrder(level3Node.has("sortOrder") ? level3Node.get("sortOrder").asLong() : 0L);
|
|
|
+ level3Sub.setStatus(level3Node.has("status") ? level3Node.get("status").asLong() : 1L);
|
|
|
+ level3Sub.setSyncCategoryId(level3Id);
|
|
|
+ categorySubMapper.insert(level3Sub);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
+ log.error("解析 remark JSON 数据失败", e);
|
|
|
+ throw new RuntimeException("解析分类数据失败", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ bo.setId(add.getId());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改分类设置主
|
|
|
+ *
|
|
|
+ * @param bo 分类设置主
|
|
|
+ * @return 是否修改成功
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Boolean updateByBo(DkhCategoryMainBo bo) {
|
|
|
+ DkhCategoryMain update = MapstructUtils.convert(bo, DkhCategoryMain.class);
|
|
|
+ validEntityBeforeSave(update);
|
|
|
+
|
|
|
+ // 先更新主表数据
|
|
|
+ boolean flag = baseMapper.updateById(update) > 0;
|
|
|
+ if (flag) {
|
|
|
+ // 从数据库获取 syncCategoryId,避免前端不传导致条件不满足
|
|
|
+ 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,实现远程增量更新
|
|
|
+ List<CategoryDto> newCategoryTree = buildCategoryTreeFromSubMenus(
|
|
|
+ bo.getName(),
|
|
|
+ subMenus,
|
|
|
+ syncCategoryId,
|
|
|
+ oldNameToSyncId
|
|
|
+ );
|
|
|
+ remoteCategoryService.updateCategoryTree(syncCategoryId, newCategoryTree);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 从远程重新获取完整分类树,获取所有分类的最新ID(含新增分类)
|
|
|
+ List<CategoryDto> remoteTree = remoteCategoryService.getCategoryTreeById(syncCategoryId);
|
|
|
+ Map<String, Long> remoteNameToId = buildRemoteNameToIdMap(remoteTree);
|
|
|
+
|
|
|
+ // 删除旧子菜单,重新保存(带远程 syncCategoryId)
|
|
|
+ categorySubMapper.delete(Wrappers.<DkhCategorySub>lambdaQuery()
|
|
|
+ .eq(DkhCategorySub::getMainCategoryId, update.getId()));
|
|
|
+ saveCategorySubs(update.getId(), bo, remoteNameToId);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("更新分类树失败", e);
|
|
|
+ // 分类树更新失败时,仍然更新本地 sub 表(不带远程ID)
|
|
|
+ categorySubMapper.delete(Wrappers.<DkhCategorySub>lambdaQuery()
|
|
|
+ .eq(DkhCategorySub::getMainCategoryId, update.getId()));
|
|
|
+ saveCategorySubs(update.getId(), bo, null);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 无远程同步时,只更新本地 sub 表
|
|
|
+ categorySubMapper.delete(Wrappers.<DkhCategorySub>lambdaQuery()
|
|
|
+ .eq(DkhCategorySub::getMainCategoryId, update.getId()));
|
|
|
+ saveCategorySubs(update.getId(), bo, null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return flag;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从 subMenus 构建分类树 DTO 列表(树形结构)
|
|
|
+ */
|
|
|
+ private List<CategoryDto> buildCategoryTreeFromSubMenus(String categoryName, JsonNode subMenus, Long rootCategoryId, Map<String, Long> nameToSyncId) {
|
|
|
+ List<CategoryDto> result = new ArrayList<>();
|
|
|
+
|
|
|
+ CategoryDto rootDto = new CategoryDto();
|
|
|
+ rootDto.setId(rootCategoryId);
|
|
|
+ rootDto.setCategoryName(categoryName);
|
|
|
+ rootDto.setParentId(0L);
|
|
|
+ rootDto.setClassLevel(1L);
|
|
|
+ rootDto.setDataSource("youyi");
|
|
|
+ rootDto.setPlatform(4L);
|
|
|
+
|
|
|
+ List<CategoryDto> level2Children = new ArrayList<>();
|
|
|
+ if (subMenus != null && subMenus.isArray()) {
|
|
|
+ for (JsonNode level2Node : subMenus) {
|
|
|
+ if (level2Node.has("level") && level2Node.get("level").asInt() == 1) {
|
|
|
+ JsonNode nestedChildren = level2Node.get("children");
|
|
|
+ if (nestedChildren != null && nestedChildren.isArray()) {
|
|
|
+ for (JsonNode nestedChild : nestedChildren) {
|
|
|
+ level2Children.add(buildCategoryDtoFromNode(nestedChild, rootCategoryId, 2L, nameToSyncId));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ level2Children.add(buildCategoryDtoFromNode(level2Node, rootCategoryId, 2L, nameToSyncId));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rootDto.setChildren(level2Children);
|
|
|
+ result.add(rootDto);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从 JSON 节点构建 CategoryDto(递归),优先从 nameToSyncId 映射获取 ID
|
|
|
+ */
|
|
|
+ private CategoryDto buildCategoryDtoFromNode(JsonNode node, Long parentId, Long classLevel, Map<String, Long> nameToSyncId) {
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(4L);
|
|
|
+
|
|
|
+ JsonNode childrenNode = node.get("children");
|
|
|
+ if (childrenNode != null && childrenNode.isArray() && !childrenNode.isEmpty()) {
|
|
|
+ List<CategoryDto> children = new ArrayList<>();
|
|
|
+ for (JsonNode childNode : childrenNode) {
|
|
|
+ children.add(buildCategoryDtoFromNode(childNode,
|
|
|
+ dto.getId() != null ? dto.getId() : parentId, classLevel + 1, nameToSyncId));
|
|
|
+ }
|
|
|
+ dto.setChildren(children);
|
|
|
+ }
|
|
|
+
|
|
|
+ return dto;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存子菜单数据到本地 dkh_category_sub 表
|
|
|
+ *
|
|
|
+ * @param mainCategoryId 主分类ID
|
|
|
+ * @param bo 分类设置主
|
|
|
+ * @param nameToSyncId 远程分类名称→ID映射(用于回填 syncCategoryId),可为null
|
|
|
+ */
|
|
|
+ private void saveCategorySubs(Long mainCategoryId, DkhCategoryMainBo bo, Map<String, Long> nameToSyncId) {
|
|
|
+ try {
|
|
|
+ if (StringUtils.isNotBlank(bo.getPanelConfigJson())) {
|
|
|
+ JsonNode rootNode = objectMapper.readTree(bo.getPanelConfigJson());
|
|
|
+ JsonNode subMenus = rootNode.get("subMenus");
|
|
|
+
|
|
|
+ if (subMenus != null && subMenus.isArray()) {
|
|
|
+ for (JsonNode level2Node : subMenus) {
|
|
|
+ String level2Name = level2Node.has("name") ? level2Node.get("name").asText() : null;
|
|
|
+ DkhCategorySub level2Sub = new DkhCategorySub();
|
|
|
+ level2Sub.setCustomerId(bo.getCustomerId());
|
|
|
+ level2Sub.setMainCategoryId(mainCategoryId);
|
|
|
+ level2Sub.setParentId(0L);
|
|
|
+ level2Sub.setName(level2Name);
|
|
|
+ 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));
|
|
|
+ }
|
|
|
+ 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;
|
|
|
+ DkhCategorySub level3Sub = new DkhCategorySub();
|
|
|
+ level3Sub.setCustomerId(bo.getCustomerId());
|
|
|
+ level3Sub.setMainCategoryId(mainCategoryId);
|
|
|
+ level3Sub.setParentId(level2Sub.getId());
|
|
|
+ level3Sub.setName(level3Name);
|
|
|
+ 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));
|
|
|
+ }
|
|
|
+ categorySubMapper.insert(level3Sub);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("保存子菜单数据失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从远程分类树构建名称→ID映射
|
|
|
+ * key: "classLevel:categoryName" → value: remoteId
|
|
|
+ */
|
|
|
+ private Map<String, Long> buildRemoteNameToIdMap(List<CategoryDto> remoteTree) {
|
|
|
+ Map<String, Long> map = new HashMap<>();
|
|
|
+ if (remoteTree == null) {
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+ for (CategoryDto dto : remoteTree) {
|
|
|
+ if (dto.getId() != null && StringUtils.isNotBlank(dto.getCategoryName())) {
|
|
|
+ map.put(dto.getClassLevel() + ":" + dto.getCategoryName(), dto.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存前的数据校验
|
|
|
+ */
|
|
|
+ private void validEntityBeforeSave(DkhCategoryMain entity) {
|
|
|
+ //TODO 做一些数据校验,如唯一约束
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充解析后的字段(tags、subMenus、panelData)
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private void fillParsedFields(DkhCategoryMainVo vo) {
|
|
|
+ try {
|
|
|
+ // 解析 tagsJson → List
|
|
|
+ if (StringUtils.isNotBlank(vo.getTagsJson())) {
|
|
|
+ vo.setTags(objectMapper.readValue(vo.getTagsJson(),
|
|
|
+ new TypeReference<List<Map<String, Object>>>() {
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("解析 tagsJson 失败: {}", vo.getTagsJson());
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ // 解析 panelConfigJson → subMenus + panelData
|
|
|
+ if (StringUtils.isNotBlank(vo.getPanelConfigJson())) {
|
|
|
+ Map<String, Object> config = objectMapper.readValue(vo.getPanelConfigJson(),
|
|
|
+ new TypeReference<Map<String, Object>>() {
|
|
|
+ });
|
|
|
+
|
|
|
+ // 提取 subMenus
|
|
|
+ if (config.containsKey("subMenus")) {
|
|
|
+ List<Map<String, Object>> subMenus = (List<Map<String, Object>>) config.get("subMenus");
|
|
|
+ // 注入 syncCategoryId
|
|
|
+ injectSyncCategoryId(vo.getId(), subMenus);
|
|
|
+ vo.setSubMenus(subMenus);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建 panelData(排除 subMenus,保留 mainTitle/subTitle/notes/groups)
|
|
|
+ Map<String, Object> panelData = new java.util.LinkedHashMap<>();
|
|
|
+ if (config.containsKey("mainTitle")) {
|
|
|
+ panelData.put("mainTitle", config.get("mainTitle"));
|
|
|
+ }
|
|
|
+ if (config.containsKey("subTitle")) {
|
|
|
+ panelData.put("subTitle", config.get("subTitle"));
|
|
|
+ }
|
|
|
+ if (config.containsKey("notes")) {
|
|
|
+ panelData.put("notes", config.get("notes"));
|
|
|
+ }
|
|
|
+ if (config.containsKey("groups")) {
|
|
|
+ panelData.put("groups", config.get("groups"));
|
|
|
+ }
|
|
|
+ vo.setPanelData(panelData);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("解析 panelConfigJson 失败: {}", vo.getPanelConfigJson());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从 dkh_category_sub 表查询 syncCategoryId,注入到 subMenus 树中各节点
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private void injectSyncCategoryId(Long mainCategoryId, List<Map<String, Object>> subMenus) {
|
|
|
+ if (mainCategoryId == null || subMenus == null || subMenus.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 查询本地子分类记录
|
|
|
+ List<DkhCategorySub> subs = categorySubMapper.selectList(
|
|
|
+ Wrappers.<DkhCategorySub>lambdaQuery()
|
|
|
+ .eq(DkhCategorySub::getMainCategoryId, mainCategoryId));
|
|
|
+ if (subs.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 构建 level:name → syncCategoryId 映射
|
|
|
+ Map<String, Long> nameToSyncId = new HashMap<>();
|
|
|
+ for (DkhCategorySub sub : subs) {
|
|
|
+ if (sub.getSyncCategoryId() != null && StringUtils.isNotBlank(sub.getName())) {
|
|
|
+ nameToSyncId.put(sub.getLevel() + ":" + sub.getName(), sub.getSyncCategoryId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 递归注入到 subMenus 树
|
|
|
+ injectSyncCategoryIdRecursive(subMenus, nameToSyncId, 2L);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 递归遍历 subMenus 树,注入 syncCategoryId
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private void injectSyncCategoryIdRecursive(List<Map<String, Object>> nodes, Map<String, Long> nameToSyncId, Long currentLevel) {
|
|
|
+ if (nodes == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (Map<String, Object> node : nodes) {
|
|
|
+ // 从 nameToSyncId 映射中查找并注入 syncCategoryId
|
|
|
+ String name = (String) node.get("name");
|
|
|
+ if (StringUtils.isNotBlank(name)) {
|
|
|
+ Long syncId = nameToSyncId.get(currentLevel + ":" + name);
|
|
|
+ if (syncId != null) {
|
|
|
+ node.put("syncCategoryId", syncId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 递归处理子节点
|
|
|
+ Object children = node.get("children");
|
|
|
+ if (children instanceof List) {
|
|
|
+ List<Map<String, Object>> childNodes = (List<Map<String, Object>>) children;
|
|
|
+ if (!childNodes.isEmpty()) {
|
|
|
+ injectSyncCategoryIdRecursive(childNodes, nameToSyncId, currentLevel + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验并批量删除分类设置主信息
|
|
|
+ *
|
|
|
+ * @param ids 待删除的主键集合
|
|
|
+ * @param isValid 是否进行有效性校验
|
|
|
+ * @return 是否删除成功
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
|
|
+ if (isValid) {
|
|
|
+ //TODO 做一些业务上的校验,判断是否需要校验
|
|
|
+ }
|
|
|
+ return baseMapper.deleteByIds(ids) > 0;
|
|
|
+ }
|
|
|
+}
|