diff --git a/adc-da-report/src/main/java/com/adc/da/report/constant/TreeLabelConstants.java b/adc-da-report/src/main/java/com/adc/da/report/constant/TreeLabelConstants.java new file mode 100644 index 0000000..0ccc7b6 --- /dev/null +++ b/adc-da-report/src/main/java/com/adc/da/report/constant/TreeLabelConstants.java @@ -0,0 +1,13 @@ +package com.adc.da.report.constant; + +/** + * @author Caihaohan + */ +public class TreeLabelConstants { + + public static final Integer DELETED = 1; + + public static final Integer UNDELETE = 0; + + public static final String ROOT_TAG_PARENT_ID = "0"; +} diff --git a/adc-da-report/src/main/java/com/adc/da/report/controller/TreeLabelManagerController.java b/adc-da-report/src/main/java/com/adc/da/report/controller/TreeLabelManagerController.java new file mode 100644 index 0000000..dd4c4cc --- /dev/null +++ b/adc-da-report/src/main/java/com/adc/da/report/controller/TreeLabelManagerController.java @@ -0,0 +1,76 @@ +package com.adc.da.report.controller; + +import cn.hutool.core.convert.Convert; +import com.adc.da.report.eo.TreeLabelEntity; +import com.adc.da.report.service.ITreeLabelService; +import com.adc.da.report.vo.TreeLabelVo; +import com.adc.da.util.http.ResponseMessage; +import com.adc.da.util.http.Result; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.subject.ExecutionException; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Caihaohan + */ +@Slf4j +@RestController +@Api(tags = "树型标签管理") +@RequestMapping("/${restPath}/tree-label") +public class TreeLabelManagerController { + + @Resource + private ITreeLabelService iTreeLabelService; + + + /** + * 新增或编辑标签 + * + * @param treeLabelVo + * @return + */ + @ApiOperation("新增或编辑标签") + @PostMapping("/add") + public ResponseMessage add(@Valid @RequestBody TreeLabelVo treeLabelVo) { + TreeLabelEntity treeLabelEntity = Convert.convert(TreeLabelEntity.class, treeLabelVo); + iTreeLabelService.saveOrUpdateTag(treeLabelEntity); + return Result.success(); + } + + /** + * 标签列表 + * + * @return + * @throws ExecutionException + * @throws InterruptedException + */ + @ApiOperation("标签列表") + @GetMapping("/list") + public ResponseMessage list(@RequestParam(value = "like", required = false) String like + ) throws ExecutionException, InterruptedException { + List rootLabel = iTreeLabelService.getTreeLabellist(like); + return Result.success(rootLabel); + } + + @ApiOperation("标签删除|单个") + @PostMapping("/delete/{id}") + public ResponseMessage delete(@PathVariable("id") String id) { + Map map = new HashMap<>(); + String status = "0"; + boolean isDelete = iTreeLabelService.deleteById(id); + if (!isDelete) { + status = "1"; + } + map.put("status", status); + return Result.success(map); + } + +} diff --git a/adc-da-report/src/main/java/com/adc/da/report/dao/mysql/TreeLabelDao.java b/adc-da-report/src/main/java/com/adc/da/report/dao/mysql/TreeLabelDao.java new file mode 100644 index 0000000..647b8de --- /dev/null +++ b/adc-da-report/src/main/java/com/adc/da/report/dao/mysql/TreeLabelDao.java @@ -0,0 +1,24 @@ +package com.adc.da.report.dao.mysql; + +import com.adc.da.report.eo.TreeLabelEntity; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author ThinkBook +* @description 针对表【ts_tree_label】的数据库操作Mapper +* @createDate 2023-04-18 10:18:44 +* @Entity com.adc.da.report.eo.TreeLabelEntity +*/ +public interface TreeLabelDao extends BaseMapper { + + /** + * 获取当前层级标签中最大的orderNum + * @param parentId + * @return + */ + int getMaxNum(String parentId); +} + + + + diff --git a/adc-da-report/src/main/java/com/adc/da/report/eo/TreeLabelEntity.java b/adc-da-report/src/main/java/com/adc/da/report/eo/TreeLabelEntity.java new file mode 100644 index 0000000..3159e44 --- /dev/null +++ b/adc-da-report/src/main/java/com/adc/da/report/eo/TreeLabelEntity.java @@ -0,0 +1,59 @@ +package com.adc.da.report.eo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * + * @author Caihaohan + * @TableName ts_tree_label + */ +@TableName(value ="ts_tree_label") +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class TreeLabelEntity implements Serializable { + /** + * + */ + @TableId(value = "id",type = IdType.INPUT) + private String id; + + /** + * + */ + private String name; + + /** + * + */ + private String parentId; + + /** + * + */ + private String createDate; + + /** + * + */ + private Integer orderNum; + + /** + * 0代表未删除,1代表已删除 + */ + private Integer delFlag; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; + +} \ No newline at end of file diff --git a/adc-da-report/src/main/java/com/adc/da/report/service/ITreeLabelService.java b/adc-da-report/src/main/java/com/adc/da/report/service/ITreeLabelService.java new file mode 100644 index 0000000..260facf --- /dev/null +++ b/adc-da-report/src/main/java/com/adc/da/report/service/ITreeLabelService.java @@ -0,0 +1,41 @@ +package com.adc.da.report.service; + +import com.adc.da.report.eo.TreeLabelEntity; +import com.adc.da.report.vo.TreeLabelVo; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** +* @author ThinkBook +* @description 针对表【ts_tree_label】的数据库操作Service +* @createDate 2023-04-18 10:18:44 +*/ +public interface ITreeLabelService extends IService { + + /** + * 返回树形结构 + * + * @return + */ + List getTreeLabellist(String like); + + + /** + * 插入或更新标签 + * @param treeLabelEntity + */ + void saveOrUpdateTag(TreeLabelEntity treeLabelEntity); + + /** + * 自动维护顺序的删除标签方法 + */ + boolean deleteByIdAutoOrder(String id); + + /** + * 删除标签 + * @param id + * @return + */ + boolean deleteById(String id); +} diff --git a/adc-da-report/src/main/java/com/adc/da/report/service/impl/ITreeLabelServiceImpl.java b/adc-da-report/src/main/java/com/adc/da/report/service/impl/ITreeLabelServiceImpl.java new file mode 100644 index 0000000..46a2869 --- /dev/null +++ b/adc-da-report/src/main/java/com/adc/da/report/service/impl/ITreeLabelServiceImpl.java @@ -0,0 +1,165 @@ +package com.adc.da.report.service.impl; + +import cn.hutool.core.convert.Convert; +import com.adc.da.report.constant.TreeLabelConstants; +import com.adc.da.report.vo.TreeLabelVo; +import com.adc.da.util.exception.AdcDaBaseException; +import com.adc.da.util.utils.StringUtils; +import com.adc.da.util.utils.UUID; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.adc.da.report.eo.TreeLabelEntity; +import com.adc.da.report.service.ITreeLabelService; +import com.adc.da.report.dao.mysql.TreeLabelDao; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.text.SimpleDateFormat; +import java.util.ArrayList; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author ThinkBook + * @description 针对表【ts_tree_label】的数据库操作Service实现 + * @createDate 2023-04-18 10:18:44 + */ +@Service +public class ITreeLabelServiceImpl extends ServiceImpl + implements ITreeLabelService { + + @Resource + private TreeLabelDao treeLabelDao; + + + @Override + public List getTreeLabellist(String like) { + //查询所有未删除的标签 + LambdaQueryWrapper treeLabelEntityWrapper = new LambdaQueryWrapper<>(); + treeLabelEntityWrapper.eq(TreeLabelEntity::getDelFlag, TreeLabelConstants.UNDELETE); + List treeLabelEntities = treeLabelDao.selectList(treeLabelEntityWrapper); + //找出根节点 + TreeLabelEntity rootTag = treeLabelEntities.stream(). + filter(treeLabelEntity -> + TreeLabelConstants.ROOT_TAG_PARENT_ID.equals(treeLabelEntity.getParentId())) + .collect(Collectors.toList()).get(0); + List treeLabelVos = Convert.toList(TreeLabelVo.class, treeLabelEntities); + + //分组排序 + Map> groupedLabelVos = treeLabelVos.stream() + .collect(Collectors.groupingBy(TreeLabelVo::getParentId)); + //排序 + Map> sortedGroupedLabelVos = groupedLabelVos.entrySet().stream() + .map(entry -> { + List sortedList = entry.getValue(); + sortedList.sort(Comparator.comparing(TreeLabelVo::getOrderNum)); + return new AbstractMap.SimpleEntry<>(entry.getKey(), sortedList); + }) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + //合并 + List labelVoList = sortedGroupedLabelVos.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + //组装成树形结构 + List tree = createTree(rootTag.getParentId(), labelVoList); + //模糊查询 + if (StringUtils.isNoneBlank(like)) { + TreeLabelVo treeLabelVo = filterByName(tree.get(0), like); + if (Objects.nonNull(treeLabelVo)) { + return Collections.singletonList(treeLabelVo); + } + return Collections.singletonList(Convert.convert(TreeLabelVo.class, rootTag)); + } + return tree; + } + + @Override + public void saveOrUpdateTag(TreeLabelEntity entity) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //不能和根节点的父ID相同 + if (TreeLabelConstants.ROOT_TAG_PARENT_ID.equals(entity.getParentId())) { + throw new AdcDaBaseException("不能和根节点的上级标签相同"); + } + int count = treeLabelDao.selectCount(new QueryWrapper() + .eq("id", entity.getParentId())); + if (count == 0) { + throw new AdcDaBaseException("上级标签不存在"); + } + + //新增标签 + if (StringUtils.isEmpty(entity.getId())) { + entity.setId(UUID.randomUUID10()); + entity.setCreateDate(format.format(new Date())); + treeLabelDao.insert(entity); + } else { + //编辑标签 + treeLabelDao.updateById(entity); + } + } + + @Override + public boolean deleteByIdAutoOrder(String id) { + TreeLabelEntity labelEntity = treeLabelDao.selectById(id); + String parentId = labelEntity.getParentId(); + int currentNum = labelEntity.getOrderNum(); + int maxNum = treeLabelDao.getMaxNum(parentId); + //删除标签 + treeLabelDao.delete(new QueryWrapper().eq("id", id)); + //如果删除的不是最后一个标签,需要移动前面的标签 + if (currentNum != maxNum) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.gt(TreeLabelEntity::getOrderNum, currentNum) + .le(TreeLabelEntity::getOrderNum, maxNum) + .eq(TreeLabelEntity::getParentId, parentId); + List labelList = treeLabelDao.selectList(wrapper); + for (TreeLabelEntity entity : labelList) { + entity.setOrderNum(entity.getOrderNum() - 1); + treeLabelDao.updateById(entity); + } + } + return true; + } + + @Override + public boolean deleteById(String id) { + int i = treeLabelDao.deleteById(id); + return i != 0; + } + + private List createTree(String rootParentId, List treeLabelVos) { + List tree = new ArrayList<>(); + for (TreeLabelVo label : treeLabelVos) { + if (label.getParentId().equals(rootParentId)) { + label.setChildLabel(createTree(label.getId(), treeLabelVos)); + tree.add(label); + } + } + return tree; + } + + public static TreeLabelVo filterByName(TreeLabelVo root, String name) { + TreeLabelVo newRoot = new TreeLabelVo(); + newRoot.setId(root.getId()); + newRoot.setName(root.getName()); + newRoot.setParentId(root.getParentId()); + newRoot.setOrderNum(root.getOrderNum()); + List childLabel = new ArrayList<>(); + if (root.getChildLabel() != null) { + for (TreeLabelVo child : root.getChildLabel()) { + TreeLabelVo newChild = filterByName(child, name); + if (newChild != null) { + childLabel.add(newChild); + } + } + } + newRoot.setChildLabel(childLabel.isEmpty() ? null : childLabel); + return root.getName().contains(name) || !childLabel.isEmpty() ? newRoot : null; + } +} + + + + diff --git a/adc-da-report/src/main/java/com/adc/da/report/vo/TreeLabelVo.java b/adc-da-report/src/main/java/com/adc/da/report/vo/TreeLabelVo.java new file mode 100644 index 0000000..438a991 --- /dev/null +++ b/adc-da-report/src/main/java/com/adc/da/report/vo/TreeLabelVo.java @@ -0,0 +1,51 @@ +package com.adc.da.report.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; +import java.util.ArrayList; +import java.util.List; + +/** + * @author ThinkBook + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class TreeLabelVo { + + /** + * id + */ + private String id; + + /** + * 标签名称 + */ + @NotBlank(message = "名称不能为空") + private String name; + + /** + * 父id + */ + private String parentId; + + /** + * + */ + private Integer orderNum; + + /** + * 子标签 + */ + private List childLabel; + + public TreeLabelVo(String parentId) { + this.parentId = parentId; + this.childLabel = new ArrayList<>(); + } +} diff --git a/adc-da-report/src/main/resources/mapper/TreeLabelDao.xml b/adc-da-report/src/main/resources/mapper/TreeLabelDao.xml new file mode 100644 index 0000000..ec9f416 --- /dev/null +++ b/adc-da-report/src/main/resources/mapper/TreeLabelDao.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/adc-da-report/target/classes/com/adc/da/report/service/impl/IReportServiceImpl.class b/adc-da-report/target/classes/com/adc/da/report/service/impl/IReportServiceImpl.class index aa30609..3f65627 100644 Binary files a/adc-da-report/target/classes/com/adc/da/report/service/impl/IReportServiceImpl.class and b/adc-da-report/target/classes/com/adc/da/report/service/impl/IReportServiceImpl.class differ