feat: 实现树形数据接口
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminMenuController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminMenuController.java
index 4d03563..4bc4cb8 100644
--- a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminMenuController.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminMenuController.java
@@ -34,6 +34,7 @@
 import com.supwisdom.institute.backend.system.api.vo.response.PermissionTreeResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.PermissionUpdateResponseData;
 import com.supwisdom.institute.backend.system.domain.entity.Permission;
+import com.supwisdom.institute.backend.system.domain.model.PermissionTreeNode;
 import com.supwisdom.institute.backend.system.domain.service.PermissionService;
 
 @Api(value = "SystemAdminMenu", tags = { "SystemAdminMenu" }, description = "菜单的操作接口")
@@ -172,9 +173,9 @@
     Map<String, Object> mapBean = new HashMap<String, Object>();
     mapBean.put("type", Permission.TYPE_MENU);
 
-    List<Permission> permissions = permissionService.selectPermissionTree(mapBean);
+    PermissionTreeNode tree = permissionService.selectPermissionTree(mapBean);
 
-    PermissionTreeResponseData data = PermissionTreeResponseData.of(permissions);
+    PermissionTreeResponseData data = PermissionTreeResponseData.of(tree);
 
     return new DefaultApiResponse<PermissionTreeResponseData>(data);
   }
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionTreeResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionTreeResponseData.java
index 1f885fc..f4724e1 100644
--- a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionTreeResponseData.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionTreeResponseData.java
@@ -1,9 +1,11 @@
 package com.supwisdom.institute.backend.system.api.vo.response;
 
-import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
 
 import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
-import com.supwisdom.institute.backend.system.domain.entity.Permission;
+import com.supwisdom.institute.backend.system.domain.model.PermissionTreeNode;
 
 public class PermissionTreeResponseData implements IApiResponseData {
 
@@ -11,10 +13,19 @@
    * 
    */
   private static final long serialVersionUID = -6659447453323545811L;
+  
+  public PermissionTreeResponseData(PermissionTreeNode tree) {
+    this.tree = tree;
+  }
+  
+  @Getter
+  @Setter
+  private PermissionTreeNode tree;
 
-  public static PermissionTreeResponseData of(List<Permission> permissions) {
-    // TODO Auto-generated method stub
-    return null;
+  public static PermissionTreeResponseData of(PermissionTreeNode tree) {
+    PermissionTreeResponseData data = new PermissionTreeResponseData(tree);
+    
+    return data;
   }
 
 }
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Permission.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Permission.java
index 72e2184..449123b 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Permission.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Permission.java
@@ -14,6 +14,8 @@
    * 
    */
   private static final long serialVersionUID = -8834200833972243635L;
+  
+  public static final String ROOT_PARENT_ID = "0";
 
   public static final String TYPE_MENU = "2";
   public static final String TYPE_OPERATION = "3";
@@ -156,19 +158,19 @@
     this.level = level;
   }
 
-  public int getLft() {
+  public Integer getLft() {
     return lft;
   }
 
-  public void setLft(int lft) {
+  public void setLft(Integer lft) {
     this.lft = lft;
   }
 
-  public int getRgt() {
+  public Integer getRgt() {
     return rgt;
   }
 
-  public void setRgt(int rgt) {
+  public void setRgt(Integer rgt) {
     this.rgt = rgt;
   }
 
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/model/PermissionTreeNode.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/model/PermissionTreeNode.java
new file mode 100644
index 0000000..0f93a47
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/model/PermissionTreeNode.java
@@ -0,0 +1,24 @@
+package com.supwisdom.institute.backend.system.domain.model;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import com.supwisdom.institute.backend.common.framework.model.IModel;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+@ToString
+public class PermissionTreeNode extends Permission implements IModel {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 6984458902464386215L;
+  
+  @Getter
+  @Setter
+  List<PermissionTreeNode> children;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/PermissionRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/PermissionRepository.java
index 42b70c8..0768adb 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/PermissionRepository.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/PermissionRepository.java
@@ -5,16 +5,23 @@
 import java.util.Map;
 import java.util.Optional;
 
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
 import javax.transaction.Transactional;
 
 import org.springframework.data.domain.Example;
 import org.springframework.data.domain.ExampleMatcher;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
+import org.springframework.util.StringUtils;
 
 import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
 import com.supwisdom.institute.backend.common.util.MapBeanUtils;
@@ -23,8 +30,88 @@
 @Repository
 @Transactional
 public interface PermissionRepository extends BaseJpaRepository<Permission> {
+  
 
   @Override
+  public default Specification<Permission> convertToSpec(Map<String, Object> mapBean) {
+    
+    Specification<Permission> spec = new Specification<Permission>() {
+
+      /**
+       * 
+       */
+      private static final long serialVersionUID = 9071470982419099273L;
+
+      @Override
+      public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+        List<Predicate> predicates = new ArrayList<>();
+        
+        if (mapBean != null) {
+
+          if (MapBeanUtils.getBoolean(mapBean, "deleted") != null) {
+            predicates.add(criteriaBuilder.equal(root.get("deleted"), MapBeanUtils.getBoolean(mapBean, "deleted")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "code"))) {
+            predicates.add(criteriaBuilder.like(root.get("code"), "%" + MapBeanUtils.getString(mapBean, "code") + "%"));
+          }
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "name"))) {
+            predicates.add(criteriaBuilder.like(root.get("name"), "%" + MapBeanUtils.getString(mapBean, "name") + "%"));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "status"))) {
+            predicates.add(criteriaBuilder.equal(root.get("status"), MapBeanUtils.getString(mapBean, "status")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "type"))) {
+            predicates.add(criteriaBuilder.equal(root.get("type"), MapBeanUtils.getString(mapBean, "type")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "url"))) {
+            predicates.add(criteriaBuilder.like(root.get("url"), "%" + MapBeanUtils.getString(mapBean, "url") + "%"));
+          }
+
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "parentId"))) {
+            predicates.add(criteriaBuilder.equal(root.get("parentId"), MapBeanUtils.getString(mapBean, "parentId")));
+          }
+
+//          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "grantTimeBegin"))) {
+//            String grantTimeBegin = MapBeanUtils.getString(mapBean, "grantTimeBegin");
+//            Date d = DateUtil.parseDate(grantTimeBegin+" 00:00:00", "yyyy-MM-dd HH:mm:ss");
+//            
+//            if (d != null) {
+//              predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("grantTime"), d));
+//            }
+//          }
+//
+//          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "grantTimeEnd"))) {
+//            String grantTimeEnd = MapBeanUtils.getString(mapBean, "grantTimeEnd");
+//            Date d = DateUtil.parseDate(grantTimeEnd+" 23:59:59", "yyyy-MM-dd HH:mm:ss");
+//            
+//            if (d != null) {
+//              predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("grantTime"), d));
+//            }
+//          }
+
+          List<Predicate> predicatesKeyword = new ArrayList<>();
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "keyword"))) {
+            predicatesKeyword.add(criteriaBuilder.like(root.get("username"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            predicatesKeyword.add(criteriaBuilder.like(root.get("name"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            predicatesKeyword.add(criteriaBuilder.like(root.get("memo"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            
+            predicates.add(criteriaBuilder.or(predicatesKeyword.toArray(new Predicate[predicatesKeyword.size()])));
+          }
+        }
+        
+        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+      }
+      
+    };
+    
+    return spec;
+  }
+  
+  @Override
   public default Page<Permission> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
     if (loadAll) {
       pageIndex = 0;
@@ -297,4 +384,26 @@
     return permissions;
   }
 
+
+
+
+  public default List<Permission> selectList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    
+    Specification<Permission> spec = convertToSpec(mapBean);
+    
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Sort sort = convertToSort(orderBy);
+
+    if (sort == null) {
+      return this.findAll(spec);
+    } else {
+      return this.findAll(spec, sort);
+    }
+  }
+
+
 }
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/PermissionService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/PermissionService.java
index b00011c..d7ebd1e 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/PermissionService.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/PermissionService.java
@@ -1,15 +1,23 @@
 package com.supwisdom.institute.backend.system.domain.service;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import lombok.extern.slf4j.Slf4j;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
 import com.supwisdom.institute.backend.common.framework.service.ABaseService;
 import com.supwisdom.institute.backend.system.domain.entity.Permission;
+import com.supwisdom.institute.backend.system.domain.model.PermissionTreeNode;
 import com.supwisdom.institute.backend.system.domain.repo.PermissionRepository;
 
+@Slf4j
 @Service
 public class PermissionService extends ABaseService<Permission, PermissionRepository> {
   
@@ -21,10 +29,36 @@
   @Autowired
   private PermissionRepository permissionRepository;
 
-  public List<Permission> selectPermissionTree(Map<String, Object> mapBean) {
+  public PermissionTreeNode selectPermissionTree(Map<String, Object> mapBean) {
     
+    List<Permission> permissions = permissionRepository.selectList(true, -1, -1, mapBean, null);
     
-    return null;
+    Map<String, PermissionTreeNode> parentTreeNode = new LinkedHashMap<String, PermissionTreeNode>();
+    
+    PermissionTreeNode rootTreeNode = new PermissionTreeNode();
+    rootTreeNode.setId(Permission.ROOT_PARENT_ID);
+    rootTreeNode.setCode("ROOT");
+    rootTreeNode.setName("顶级菜单");
+    rootTreeNode.setChildren(new ArrayList<PermissionTreeNode>());
+    
+    parentTreeNode.put(rootTreeNode.getId(), rootTreeNode);
+    
+    for (Permission permission : permissions) {
+      PermissionTreeNode treeNode = EntityUtils.copy(permission, new PermissionTreeNode());
+      treeNode.setChildren(new ArrayList<PermissionTreeNode>());
+      
+      parentTreeNode.put(treeNode.getId(), treeNode);
+    }
+    
+    for (PermissionTreeNode treeNode : parentTreeNode.values()) {
+      if (!parentTreeNode.containsKey(treeNode.getParentId())) {
+        continue;
+      }
+      
+      parentTreeNode.get(treeNode.getParentId()).getChildren().add(treeNode);
+    }
+    
+    return rootTreeNode;
   }
 
 }