功能维护、角色管理
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/FunctionDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/FunctionDao.java
index 619a530..1e08ccb 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/dao/FunctionDao.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/FunctionDao.java
@@ -10,9 +10,17 @@
 import java.util.List;
 
 @Repository
-public interface FunctionDao extends JpaRepository<TFunction, String> {
-  @Query("select distinct t from TFunction t,TRoleFunction a, TOperRole b where t.id=a.functionId and a.roleId=b.roleId and b.operid=?1 order by t.orderNum ")
-  List<TFunction> getTFunctionsByOperid(String operid);
+public interface FunctionDao extends JpaRepository<TFunction, Integer> {
+    @Query("select distinct t from TFunction t,TRoleFunction a, TOperRole b where t.id=a.functionId and a.roleId=b.roleId and b.operid=?1 order by t.orderNum ")
+    List<TFunction> getTFunctionsByOperid(String operid);
 
-  Page<TFunction> findAllByNameContaining(String name,Pageable pageable);
+    Page<TFunction> findAllByNameContaining(String name, Pageable pageable);
+
+    TFunction findByName(String name);
+
+    TFunction findByNameAndIdNot(String name, Integer id);
+
+    List<TFunction> findByParentId(Integer parentId);
+
+    List<TFunction> findByIsLeaf(Integer isLeaf);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/PermissionDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/PermissionDao.java
new file mode 100644
index 0000000..767df41
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/PermissionDao.java
@@ -0,0 +1,16 @@
+package com.supwisdom.dlpay.framework.dao;
+
+import com.supwisdom.dlpay.framework.domain.TPermission;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface PermissionDao extends JpaRepository<TPermission, String> {
+    List<TPermission> findByRoleFuncId(String roleFuncId);
+
+    TPermission findByRoleFuncIdAndResid(String roleFuncId, Integer resid);
+
+    void deleteByRoleFuncId(String roleFuncId);
+
+    void deleteByRoleId(String roleId);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/ResourceDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/ResourceDao.java
index 22f5c1c..d5a81c8 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/dao/ResourceDao.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/ResourceDao.java
@@ -4,7 +4,16 @@
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
+
 @Repository
-public interface ResourceDao extends JpaRepository<TResource, String> {
+public interface ResourceDao extends JpaRepository<TResource, Integer> {
     TResource findByUri(String uri);
+
+    List<TResource> findByFunctionId(Integer functionId);
+
+    TResource findByUriAndIdNot(String uri, Integer id);
+
+    void deleteByFunctionId(Integer functionId);
+
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/RoleDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/RoleDao.java
index af771de..0baed2e 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/dao/RoleDao.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/RoleDao.java
@@ -1,6 +1,8 @@
 package com.supwisdom.dlpay.framework.dao;
 
 import com.supwisdom.dlpay.framework.domain.TRole;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.stereotype.Repository;
@@ -9,9 +11,14 @@
 
 @Repository
 public interface RoleDao extends JpaRepository<TRole, String> {
-  @Query("from TRole order by createtime asc ")
-  List<TRole> getAllRoles();
+    @Query("from TRole order by createtime asc ")
+    List<TRole> getAllRoles();
 
-  TRole findByRoleCode(String rolecode);
+    TRole findByRoleCode(String rolecode);
 
+    Page<TRole> findAllByRoleNameContaining(String roleName, Pageable pageable);
+
+    TRole findByRoleNameAndRoleIdNot(String roleName, String roleId);
+
+    TRole findByRoleName(String roleName);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/RoleFunctionDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/RoleFunctionDao.java
index de69392..565ebe6 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/dao/RoleFunctionDao.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/RoleFunctionDao.java
@@ -1,11 +1,29 @@
 package com.supwisdom.dlpay.framework.dao;
 
+import com.supwisdom.dlpay.framework.data.NodeData;
 import com.supwisdom.dlpay.framework.domain.TRoleFunction;
+import com.supwisdom.dlpay.system.bean.ZTreeNode;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
+
 @Repository
 public interface RoleFunctionDao extends JpaRepository<TRoleFunction, String> {
 
-    TRoleFunction findByRoleIdAndFunctionId(String roleId,String functionId);
+    TRoleFunction findByRoleIdAndFunctionId(String roleId, Integer functionId);
+
+    void deleteByFunctionId(Integer functionId);
+
+    List<TRoleFunction> findByRoleId(String roleId);
+
+    @Query(value = " select f.id||'' as id ,f.parentid||'' as pid,f.name,case when rf.id is null then 0 else 1 end as checked from tb_function f " +
+            " left join tb_role_function rf on rf.functionid = f.id and rf.roleid=?1 " +
+            " union all " +
+            " select r.id||'_res' as id,r.function_id||'' as pid,r.name,case when p.id is null then 0 else 1 end as checked from tb_resource  r " +
+            " left join tb_permission p on p.resid = r.id and p.roleid=?1 " , nativeQuery = true)
+    List<NodeData> findByRoleIdNative(String roleId);
+
+    void deleteByRoleId(String roleId);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/data/NodeData.java b/src/main/java/com/supwisdom/dlpay/framework/data/NodeData.java
new file mode 100644
index 0000000..19197d3
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/data/NodeData.java
@@ -0,0 +1,13 @@
+package com.supwisdom.dlpay.framework.data;
+
+public interface NodeData {
+    String getId();
+
+    String getPid();
+
+    String getName();
+
+    boolean getOpen();
+
+    Integer getChecked();
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/domain/TFunction.java b/src/main/java/com/supwisdom/dlpay/framework/domain/TFunction.java
index 8c135e8..2f3b83c 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/domain/TFunction.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/domain/TFunction.java
@@ -1,20 +1,18 @@
 package com.supwisdom.dlpay.framework.domain;
 
-import org.hibernate.annotations.GenericGenerator;
-
 import javax.persistence.*;
 
 @Entity
 @Table(name = "TB_FUNCTION")
+@SequenceGenerator(name="SEQ_FUNC",sequenceName="SEQ_FUNC",allocationSize=1)
 public class TFunction {
   @Id
-  @GenericGenerator(name = "idGenerator", strategy = "uuid")
-  @GeneratedValue(generator = "idGenerator")
-  @Column(name="ID", nullable = false, length = 32)
-  private String id;
+  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_FUNC")
+  @Column(name="ID", nullable = false)
+  private Integer id;
 
-  @Column(name="PARENTID", length = 32)
-  private String parentId;
+  @Column(name="PARENTID")
+  private Integer parentId;
 
   @Column(name="NAME", length = 32)
   private String name;
@@ -37,19 +35,19 @@
   @Column(name="LASTSAVED", length = 14)
   private String lastsaved;
 
-  public String getId() {
+  public Integer getId() {
     return id;
   }
 
-  public void setId(String id) {
+  public void setId(Integer id) {
     this.id = id;
   }
 
-  public String getParentId() {
+  public Integer getParentId() {
     return parentId;
   }
 
-  public void setParentId(String parentId) {
+  public void setParentId(Integer parentId) {
     this.parentId = parentId;
   }
 
diff --git a/src/main/java/com/supwisdom/dlpay/framework/domain/TPermission.java b/src/main/java/com/supwisdom/dlpay/framework/domain/TPermission.java
new file mode 100644
index 0000000..0d22f35
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/domain/TPermission.java
@@ -0,0 +1,56 @@
+package com.supwisdom.dlpay.framework.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "TB_PERMISSION")
+public class TPermission {
+    @Id
+    @GenericGenerator(name = "idGenerator", strategy = "uuid")
+    @GeneratedValue(generator = "idGenerator")
+    @Column(name = "ID", nullable = false, length = 32)
+    private String id;
+
+    @Column(name = "ROLE_FUNC_ID", length = 32)
+    private String roleFuncId;
+
+    @Column(name = "RESID")
+    private Integer resid;
+
+    @Column(name = "ROLEID")
+    private String roleId;
+
+    public String getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(String roleId) {
+        this.roleId = roleId;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getRoleFuncId() {
+        return roleFuncId;
+    }
+
+    public void setRoleFuncId(String roleFuncId) {
+        this.roleFuncId = roleFuncId;
+    }
+
+    public Integer getResid() {
+        return resid;
+    }
+
+    public void setResid(Integer resid) {
+        this.resid = resid;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/domain/TResource.java b/src/main/java/com/supwisdom/dlpay/framework/domain/TResource.java
index 889eaca..63044cb 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/domain/TResource.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/domain/TResource.java
@@ -1,16 +1,15 @@
 package com.supwisdom.dlpay.framework.domain;
 
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
+import javax.persistence.*;
 
 @Entity
 @Table(name = "TB_RESOURCE")
+@SequenceGenerator(name="SEQ_RES",sequenceName="SEQ_RES",allocationSize=1)
 public class TResource {
   @Id
-  @Column(name = "ID", nullable = false, length = 32)
-  private String id;
+  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_RES")
+  @Column(name = "ID", nullable = false,length = 9)
+  private Integer id;
 
   @Column(name = "CODE", nullable = false, length = 32)
   private String code;
@@ -22,13 +21,13 @@
   private String uri;
 
   @Column(name = "FUNCTION_ID", nullable = false, length = 32)
-  private String functionId;
+  private Integer functionId;
 
-  public String getId() {
+  public Integer getId() {
     return id;
   }
 
-  public void setId(String id) {
+  public void setId(Integer id) {
     this.id = id;
   }
 
@@ -56,11 +55,11 @@
     this.uri = uri;
   }
 
-  public String getFunctionId() {
+  public Integer getFunctionId() {
     return functionId;
   }
 
-  public void setFunctionId(String functionId) {
+  public void setFunctionId(Integer functionId) {
     this.functionId = functionId;
   }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/domain/TRoleFunction.java b/src/main/java/com/supwisdom/dlpay/framework/domain/TRoleFunction.java
index a621460..c5e9f05 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/domain/TRoleFunction.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/domain/TRoleFunction.java
@@ -17,7 +17,7 @@
   private String roleId;
 
   @Column(name="FUNCTIONID", nullable = false, length = 32)
-  private String functionId;
+  private Integer functionId;
 
   @Column(name="PERMISSIONS", length = 200)
   private String permissions;
@@ -38,11 +38,11 @@
     this.roleId = roleId;
   }
 
-  public String getFunctionId() {
+  public Integer getFunctionId() {
     return functionId;
   }
 
-  public void setFunctionId(String functionId) {
+  public void setFunctionId(Integer functionId) {
     this.functionId = functionId;
   }
 
diff --git a/src/main/java/com/supwisdom/dlpay/system/bean/ZTreeNode.java b/src/main/java/com/supwisdom/dlpay/system/bean/ZTreeNode.java
new file mode 100644
index 0000000..9d50273
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/system/bean/ZTreeNode.java
@@ -0,0 +1,50 @@
+package com.supwisdom.dlpay.system.bean;
+
+
+public class ZTreeNode {
+    private String id;
+    private String pId;
+    private String name;
+    private boolean checked;
+    private boolean open;
+
+    public boolean isOpen() {
+        return open;
+    }
+
+    public void setOpen(boolean open) {
+        this.open = open;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getpId() {
+        return pId;
+    }
+
+    public void setpId(String pId) {
+        this.pId = pId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isChecked() {
+        return checked;
+    }
+
+    public void setChecked(boolean checked) {
+        this.checked = checked;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/system/controller/FunctionController.java b/src/main/java/com/supwisdom/dlpay/system/controller/FunctionController.java
index 16c598a..978819c 100644
--- a/src/main/java/com/supwisdom/dlpay/system/controller/FunctionController.java
+++ b/src/main/java/com/supwisdom/dlpay/system/controller/FunctionController.java
@@ -1,8 +1,10 @@
 package com.supwisdom.dlpay.system.controller;
 
 
+import com.supwisdom.dlpay.consume.bean.JsonResult;
 import com.supwisdom.dlpay.framework.domain.TFunction;
 import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.framework.domain.TResource;
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.framework.util.StringUtil;
 import com.supwisdom.dlpay.framework.util.WebConstant;
@@ -12,9 +14,9 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 @Controller
 public class FunctionController {
@@ -45,4 +47,85 @@
             return new PageResult<>(99, "系统查询错误");
         }
     }
+
+    @GetMapping("/function/loadadd")
+    public String loadadd() {
+        return "system/function/form";
+    }
+
+    @PostMapping("/function/add")
+    @ResponseBody
+    public JsonResult add(@RequestBody TFunction function) {
+        if (function != null) {
+            return functionService.saveFunction(function);
+        } else {
+            return JsonResult.error("添加失败");
+        }
+    }
+    @PostMapping("/function/delfunc")
+    @ResponseBody
+    public JsonResult delfunc(@RequestParam Integer funcid) {
+        return functionService.deleteFunction(funcid);
+    }
+
+    @GetMapping("/function/checkname")
+    @ResponseBody
+    public JsonResult checkname(@RequestParam String name,
+                                @RequestParam(value = "id", required = false) Integer id) {
+        TFunction function = functionService.getFunctionByNameAndId(name, id);
+        if (function == null) {
+            return JsonResult.ok();
+        } else {
+            return JsonResult.error("功能名称重复");
+        }
+    }
+
+    @GetMapping("/function/loadsubadd")
+    public String loadsubadd(Model model) {
+        List<TFunction> functionList = functionService.getParentFunction();
+        model.addAttribute("list", functionList);
+        return "system/function/subform";
+    }
+
+    @GetMapping("/function/loadres")
+    public String loadres(@RequestParam Integer functionid, Model model) {
+        TFunction function = functionService.getFunctionById(functionid);
+        List<TResource> resources = functionService.getResources(functionid);
+        model.addAttribute("function", function);
+        model.addAttribute("resources", resources);
+        return "system/function/reslist";
+    }
+    @GetMapping("/function/reslist")
+    @ResponseBody
+    public PageResult<TResource> reslist(@RequestParam Integer functionid, Model model) {
+        List<TResource> resources = functionService.getResources(functionid);
+        return new PageResult<TResource>(resources);
+    }
+    @GetMapping("/function/loadresadd")
+    public String loadresadd(Model model) {
+        List<TFunction> functionList = functionService.getLeafFunction();
+        model.addAttribute("list", functionList);
+        return "system/function/resform";
+    }
+
+    @PostMapping("/function/addres")
+    @ResponseBody
+    public JsonResult addres(@RequestBody TResource resource) {
+        if (resource != null) {
+            return functionService.saveRes(resource);
+        } else {
+            return JsonResult.error("添加失败");
+        }
+    }
+    @GetMapping("/function/editres")
+    public String loadresadd(@RequestParam Integer resid,Model model) {
+        List<TFunction> functionList = functionService.getLeafFunction();
+        model.addAttribute("list", functionList);
+        return "system/function/resform";
+    }
+    @PostMapping("/function/delres")
+    @ResponseBody
+    public JsonResult delres(@RequestParam Integer resid) {
+        return functionService.deleteResource(resid);
+    }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/system/controller/RoleController.java b/src/main/java/com/supwisdom/dlpay/system/controller/RoleController.java
index 4fb7b2b..d7c1faa 100644
--- a/src/main/java/com/supwisdom/dlpay/system/controller/RoleController.java
+++ b/src/main/java/com/supwisdom/dlpay/system/controller/RoleController.java
@@ -1,18 +1,86 @@
 package com.supwisdom.dlpay.system.controller;
 
-
+import com.supwisdom.dlpay.consume.bean.JsonResult;
+import com.supwisdom.dlpay.framework.domain.TFunction;
+import com.supwisdom.dlpay.framework.domain.TRole;
+import com.supwisdom.dlpay.framework.domain.TRoleFunction;
+import com.supwisdom.dlpay.framework.util.PageResult;
+import com.supwisdom.dlpay.framework.util.WebConstant;
+import com.supwisdom.dlpay.system.bean.FunctionSearchBean;
+import com.supwisdom.dlpay.system.bean.ZTreeNode;
+import com.supwisdom.dlpay.system.service.FunctionService;
+import com.supwisdom.dlpay.system.service.RoleService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
 
 @Controller
-@RequestMapping("/role")
 public class RoleController {
+    @Autowired
+    private RoleService roleService;
+    @Autowired
+    private FunctionService functionService;
 
-  @GetMapping("/index")
-  public String indexView(Model model) {
-    return "system/role/index";
-  }
+    @GetMapping("/role/index")
+    public String indexView() {
+        return "system/role/index";
+    }
 
+    @GetMapping("/role/list")
+    @ResponseBody
+    public PageResult<TRole> getDataList(@RequestParam("page") Integer pageNo,
+                                         @RequestParam("limit") Integer pageSize,
+                                         @RequestParam(value = "searchkey", required = false) String searchKey) {
+        try {
+            if (null == pageNo || pageNo < 1) pageNo = WebConstant.PAGENO_DEFAULT;
+            if (null == pageSize || pageSize < 1) pageSize = WebConstant.PAGESIZE_DEFAULT;
+            FunctionSearchBean searchBean = new FunctionSearchBean();
+            searchBean.setPageNo(pageNo);
+            searchBean.setFunctioname(searchKey);
+            searchBean.setPageSize(pageSize);
+            return roleService.getRolesByKey(searchBean);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new PageResult<>(99, "系统查询错误");
+        }
+    }
+
+    @GetMapping("/role/loadadd")
+    public String loadadd() {
+        return "system/role/form";
+    }
+
+    @PostMapping("/role/add")
+    @ResponseBody
+    public JsonResult add(@RequestBody TRole role) {
+        if (role != null) {
+            return roleService.saveRole(role);
+        } else {
+            return JsonResult.error("添加失败");
+        }
+    }
+
+    @GetMapping("/role/loadfunc")
+    public String loadfunc() {
+        return "system/role/func";
+    }
+
+    @PostMapping("/role/addfunc")
+    @ResponseBody
+    public JsonResult addfunc(@RequestParam String roleId,
+                              @RequestParam String funcs) {
+        return roleService.saveRoleFuncId(roleId, funcs);
+    }
+
+    @GetMapping("/role/func")
+    @ResponseBody
+    public JsonResult func(@RequestParam String roleId) {
+        List<ZTreeNode> nodes = roleService.findByRoleIdNative(roleId);
+        JsonResult result = JsonResult.ok();
+        result.put("node", nodes);
+        return result;
+    }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/system/service/FunctionService.java b/src/main/java/com/supwisdom/dlpay/system/service/FunctionService.java
index 55cc2aa..f3b07be 100644
--- a/src/main/java/com/supwisdom/dlpay/system/service/FunctionService.java
+++ b/src/main/java/com/supwisdom/dlpay/system/service/FunctionService.java
@@ -1,6 +1,8 @@
 package com.supwisdom.dlpay.system.service;
 
+import com.supwisdom.dlpay.consume.bean.JsonResult;
 import com.supwisdom.dlpay.framework.domain.TFunction;
+import com.supwisdom.dlpay.framework.domain.TResource;
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.system.bean.FunctionSearchBean;
 
@@ -10,7 +12,25 @@
 public interface FunctionService {
   List<TFunction> getFunctionsByOperid(String operid);
 
-  List<Map<String, Object>> getMenuTree(List<TFunction> funcList, String parentId);
+  List<Map<String, Object>> getMenuTree(List<TFunction> funcList, Integer parentId);
 
   PageResult<TFunction> getFunctionsByKey(FunctionSearchBean param);
+
+  TFunction getFunctionByNameAndId(String name,Integer id);
+
+  JsonResult saveFunction(TFunction function);
+
+  TFunction getFunctionById(Integer id);
+
+  JsonResult deleteFunction(Integer funcid);
+
+  List<TFunction> getParentFunction();
+
+  List<TResource> getResources(Integer function);
+
+  List<TFunction> getLeafFunction();
+
+  JsonResult saveRes(TResource resource);
+
+  JsonResult deleteResource(Integer resid);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/system/service/RoleService.java b/src/main/java/com/supwisdom/dlpay/system/service/RoleService.java
index e4b8082..3d47b83 100644
--- a/src/main/java/com/supwisdom/dlpay/system/service/RoleService.java
+++ b/src/main/java/com/supwisdom/dlpay/system/service/RoleService.java
@@ -1,8 +1,13 @@
 package com.supwisdom.dlpay.system.service;
 
+import com.supwisdom.dlpay.consume.bean.JsonResult;
+import com.supwisdom.dlpay.framework.domain.TPermission;
 import com.supwisdom.dlpay.framework.domain.TResource;
 import com.supwisdom.dlpay.framework.domain.TRole;
 import com.supwisdom.dlpay.framework.domain.TRoleFunction;
+import com.supwisdom.dlpay.framework.util.PageResult;
+import com.supwisdom.dlpay.system.bean.FunctionSearchBean;
+import com.supwisdom.dlpay.system.bean.ZTreeNode;
 
 import java.util.List;
 
@@ -13,5 +18,19 @@
 
     TResource findResourceByURI(String uri);
 
-    TRoleFunction findRoleFunctionByRoleIdAndFunctionId(String roleid, String functionid);
+    TRoleFunction findRoleFunctionByRoleIdAndFunctionId(String roleid, Integer functionid);
+
+    PageResult<TRole> getRolesByKey(FunctionSearchBean param);
+
+    JsonResult saveRole(TRole role);
+
+    List<TRoleFunction> getRoleFuncByRoleid(String roleId);
+
+    List<TPermission> findByRoleFuncId(String roleFuncId);
+
+    TPermission findByRoleFuncIdAndResid(String roleFuncId, Integer resid);
+
+    JsonResult saveRoleFuncId(String roleId, String funcs);
+
+    List<ZTreeNode> findByRoleIdNative(String roleId);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/system/service/impl/FunctionServiceImpl.java b/src/main/java/com/supwisdom/dlpay/system/service/impl/FunctionServiceImpl.java
index 41b1460..2e394b1 100644
--- a/src/main/java/com/supwisdom/dlpay/system/service/impl/FunctionServiceImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/system/service/impl/FunctionServiceImpl.java
@@ -1,7 +1,11 @@
 package com.supwisdom.dlpay.system.service.impl;
 
+import com.supwisdom.dlpay.consume.bean.JsonResult;
 import com.supwisdom.dlpay.framework.dao.FunctionDao;
+import com.supwisdom.dlpay.framework.dao.ResourceDao;
+import com.supwisdom.dlpay.framework.dao.RoleFunctionDao;
 import com.supwisdom.dlpay.framework.domain.TFunction;
+import com.supwisdom.dlpay.framework.domain.TResource;
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.framework.util.StringUtil;
 import com.supwisdom.dlpay.system.bean.FunctionSearchBean;
@@ -21,6 +25,10 @@
 public class FunctionServiceImpl implements FunctionService {
     @Autowired
     private FunctionDao functionDao;
+    @Autowired
+    private ResourceDao resourceDao;
+    @Autowired
+    private RoleFunctionDao roleFunctionDao;
 
     @Override
     public List<TFunction> getFunctionsByOperid(String operid) {
@@ -30,7 +38,7 @@
     }
 
     @Override
-    public List<Map<String, Object>> getMenuTree(List<TFunction> funcList, String parentId) {
+    public List<Map<String, Object>> getMenuTree(List<TFunction> funcList, Integer parentId) {
         List<Map<String, Object>> list = new ArrayList<>(0);
         for (TFunction func : funcList) {
             if (parentId.equals(func.getParentId())) {
@@ -58,4 +66,76 @@
         }
         return new PageResult<>(functionDao.findAll(pageable));
     }
+
+    @Override
+    public TFunction getFunctionByNameAndId(String name, Integer id) {
+        if (id != null && id != 0) {
+            return functionDao.findByNameAndIdNot(name, id);
+        }
+        return functionDao.findByName(name);
+    }
+
+    @Override
+    public JsonResult saveFunction(TFunction function) {
+        TFunction temp = getFunctionByNameAndId(function.getName(), function.getId());
+        if (temp != null) {
+            return JsonResult.error("功能名称重复");
+        }
+        if (function.getParentId() == null) {
+            function.setParentId(-1);
+        }
+        functionDao.save(function);
+        return JsonResult.ok("成功");
+    }
+
+    @Override
+    public TFunction getFunctionById(Integer id) {
+        return functionDao.getOne(id);
+    }
+
+    @Override
+    public List<TFunction> getParentFunction() {
+        return functionDao.findByIsLeaf(0);
+    }
+
+    @Override
+    public List<TResource> getResources(Integer function) {
+        return resourceDao.findByFunctionId(function);
+    }
+
+    @Override
+    public List<TFunction> getLeafFunction() {
+        return functionDao.findByIsLeaf(1);
+    }
+
+    @Override
+    public JsonResult saveRes(TResource resource) {
+        if (resource.getId() != null && resource.getId() != 0) {
+            TResource temp = resourceDao.findByUriAndIdNot(resource.getUri(), resource.getId());
+            if (temp != null) {
+                return JsonResult.error("资源路径已存在");
+            }
+        } else {
+            TResource temp = resourceDao.findByUri(resource.getUri());
+            if (temp != null) {
+                return JsonResult.error("资源路径已存在");
+            }
+        }
+        resourceDao.save(resource);
+        return JsonResult.ok("成功");
+    }
+
+    @Override
+    public JsonResult deleteResource(Integer resid) {
+        resourceDao.deleteById(resid);
+        return JsonResult.ok("成功");
+    }
+
+    @Override
+    public JsonResult deleteFunction(Integer funcid) {
+        resourceDao.deleteByFunctionId(funcid);
+        roleFunctionDao.deleteByFunctionId(funcid);
+        functionDao.deleteById(funcid);
+        return JsonResult.ok("成功");
+    }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/system/service/impl/RoleServiceImpl.java b/src/main/java/com/supwisdom/dlpay/system/service/impl/RoleServiceImpl.java
index f78b052..4796efa 100644
--- a/src/main/java/com/supwisdom/dlpay/system/service/impl/RoleServiceImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/system/service/impl/RoleServiceImpl.java
@@ -1,49 +1,162 @@
 package com.supwisdom.dlpay.system.service.impl;
 
+import com.supwisdom.dlpay.consume.bean.JsonResult;
+import com.supwisdom.dlpay.framework.dao.PermissionDao;
 import com.supwisdom.dlpay.framework.dao.ResourceDao;
 import com.supwisdom.dlpay.framework.dao.RoleDao;
 import com.supwisdom.dlpay.framework.dao.RoleFunctionDao;
+import com.supwisdom.dlpay.framework.data.NodeData;
+import com.supwisdom.dlpay.framework.domain.TPermission;
 import com.supwisdom.dlpay.framework.domain.TResource;
 import com.supwisdom.dlpay.framework.domain.TRole;
 import com.supwisdom.dlpay.framework.domain.TRoleFunction;
+import com.supwisdom.dlpay.framework.util.DateUtil;
+import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.system.bean.FunctionSearchBean;
+import com.supwisdom.dlpay.system.bean.ZTreeNode;
 import com.supwisdom.dlpay.system.service.RoleService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
 
 @Service
 public class RoleServiceImpl implements RoleService {
-  @Autowired
-  private RoleDao roleDao;
+    @Autowired
+    private RoleDao roleDao;
 
-  @Autowired
-  private ResourceDao resourceDao;
+    @Autowired
+    private ResourceDao resourceDao;
 
-  @Autowired
-  private RoleFunctionDao roleFunctionDao;
+    @Autowired
+    private RoleFunctionDao roleFunctionDao;
 
-  @Override
-  public List<TRole> findAllRoles() {
-    List<TRole> list = roleDao.getAllRoles();
-    if(!StringUtil.isEmpty(list)) return list;
-    return new ArrayList<>(0);
-  }
+    @Autowired
+    private PermissionDao permissionDao;
 
-  @Override
-  public TRole findRoleByRolecode(String rolecode) {
-    return roleDao.findByRoleCode(rolecode);
-  }
+    @Override
+    public List<TRole> findAllRoles() {
+        List<TRole> list = roleDao.getAllRoles();
+        if (!StringUtil.isEmpty(list)) return list;
+        return new ArrayList<>(0);
+    }
 
-  @Override
-  public TResource findResourceByURI(String uri) {
-    return resourceDao.findByUri(uri);
-  }
+    @Override
+    public TRole findRoleByRolecode(String rolecode) {
+        return roleDao.findByRoleCode(rolecode);
+    }
 
-  @Override
-  public TRoleFunction findRoleFunctionByRoleIdAndFunctionId(String roleid, String functionid) {
-    return roleFunctionDao.findByRoleIdAndFunctionId(roleid,functionid);
-  }
+    @Override
+    public TResource findResourceByURI(String uri) {
+        return resourceDao.findByUri(uri);
+    }
+
+    @Override
+    public TRoleFunction findRoleFunctionByRoleIdAndFunctionId(String roleid, Integer functionid) {
+        return roleFunctionDao.findByRoleIdAndFunctionId(roleid, functionid);
+    }
+
+    @Override
+    public PageResult<TRole> getRolesByKey(FunctionSearchBean param) {
+        Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize()
+                , Sort.by("createtime"));
+        if (!StringUtil.isEmpty(param.getFunctioname())) {
+            return new PageResult<>(roleDao.findAllByRoleNameContaining(param.getFunctioname(), pageable));
+        }
+        return new PageResult<>(roleDao.findAll(pageable));
+    }
+
+    @Override
+    public JsonResult saveRole(TRole role) {
+        if (!StringUtil.isEmpty(role.getRoleId())) {
+            TRole temp = roleDao.findByRoleNameAndRoleIdNot(role.getRoleName(), role.getRoleId());
+            if (temp != null) {
+                return JsonResult.error("角色名称已存在");
+            }
+            Optional<TRole> opt = roleDao.findById(role.getRoleId());
+            if (opt == null || !opt.isPresent()) {
+                return JsonResult.error("角色已被删除");
+            }
+            temp = opt.get();
+            temp.setRoleName(role.getRoleName());
+            temp.setRoleDesc(role.getRoleDesc());
+            temp.setLastsaved(DateUtil.getNow());
+            roleDao.save(temp);
+        } else {
+            TRole temp = roleDao.findByRoleName(role.getRoleName());
+            if (temp != null) {
+                return JsonResult.error("角色名称已存在");
+            }
+            role.setCreatetime(DateUtil.getNow());
+            role.setEditflag(1);
+            role.setRoleCode("ROLE_ADMIN");
+            roleDao.save(role);
+        }
+        return JsonResult.ok("成功");
+    }
+
+    @Override
+    public List<TRoleFunction> getRoleFuncByRoleid(String roleId) {
+        return roleFunctionDao.findByRoleId(roleId);
+    }
+
+
+    @Override
+    public List<TPermission> findByRoleFuncId(String roleFuncId) {
+        return permissionDao.findByRoleFuncId(roleFuncId);
+    }
+
+    @Override
+    public TPermission findByRoleFuncIdAndResid(String roleFuncId, Integer resid) {
+        return permissionDao.findByRoleFuncIdAndResid(roleFuncId, resid);
+    }
+
+    @Override
+    public JsonResult saveRoleFuncId(String roleId, String funcs) {
+        Optional<TRole> ret = roleDao.findById(roleId);
+        if (ret == null || !ret.isPresent()) {
+            return JsonResult.error("角色不存在");
+        }
+        roleFunctionDao.deleteByRoleId(roleId);
+        permissionDao.deleteByRoleId(roleId);
+        String[] datas = funcs.split(",");
+        for (String func : datas) {
+            if (func.contains("_res")) {
+                String id = func.replace("_res", "");
+                TPermission permission = new TPermission();
+                permission.setResid(Integer.valueOf(id));
+                permission.setRoleId(roleId);
+                permissionDao.save(permission);
+            } else {
+                TRoleFunction roleFunction = new TRoleFunction();
+                roleFunction.setFunctionId(Integer.valueOf(func));
+                roleFunction.setRoleId(roleId);
+                roleFunctionDao.save(roleFunction);
+            }
+        }
+        return JsonResult.ok("成功");
+    }
+
+    @Override
+    public List<ZTreeNode> findByRoleIdNative(String roleId) {
+        List<NodeData> nodeData = roleFunctionDao.findByRoleIdNative(roleId);
+        List<ZTreeNode> ret = new ArrayList<>();
+        for (NodeData data : nodeData) {
+            ZTreeNode zTreeNode = new ZTreeNode();
+            zTreeNode.setpId(data.getPid());
+            zTreeNode.setId(data.getId());
+            zTreeNode.setName(data.getName());
+            zTreeNode.setChecked(data.getChecked() == 0 ? false : true);
+            zTreeNode.setOpen(true);
+            ret.add(zTreeNode);
+        }
+        return ret;
+    }
 }
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
index 24afe10..10f6603 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
@@ -199,7 +199,7 @@
     fun menuView(@AuthenticationPrincipal operUser: UserDetails, model: Model): String {
         model.addAttribute("loginOper", operUser as TOperator)
         val funclist = functionService.getFunctionsByOperid(operUser.operid)
-        model.addAttribute("menus", functionService.getMenuTree(funclist, "-1"))
+        model.addAttribute("menus", functionService.getMenuTree(funclist, -1))
         model.addAttribute("payapiVersion", commonService.getSystemVersion())
         return "index"
     }
diff --git a/src/main/resources/static/custom/module/admin.js b/src/main/resources/static/custom/module/admin.js
index 344c44d..334e29e 100755
--- a/src/main/resources/static/custom/module/admin.js
+++ b/src/main/resources/static/custom/module/admin.js
@@ -89,24 +89,26 @@
             return layer.open(param);

         },

         

-        go:function(url,data,success){

+        go:function(url,data,success,error){

         	  $.ajax({

         		  url: url,

         		  data: data,

         		  async: false,

         		  dataType: 'json',

         		  type: 'post',

-        		   success: success

+        		  success: success,

+                  error:error

         	  })

         },

-        dgo:function(url,data,success){

+        dgo:function(url,data,success,error){

       	  $.ajax({

       		  url: url,

       		  data: data,

       		  async: false,

       		  dataType: 'json',

       		  type: 'get',

-      		   success: success

+      		  success: success,

+              error:error

       	  })

       },

         // 封装ajax请求,返回数据类型为json

diff --git a/src/main/resources/templates/system/function/form.html b/src/main/resources/templates/system/function/form.html
index cd67f9f..94ef8cc 100755
--- a/src/main/resources/templates/system/function/form.html
+++ b/src/main/resources/templates/system/function/form.html
@@ -1,43 +1,117 @@
-<div class="layui-form" lay-filter="layuiadmin-form-role" id="function-form" style="padding: 20px 30px 0 0;">

+<!-- operator表单弹窗 -->

+<form id="form" lay-filter="form" class="layui-form model-form">

+    <input name="id" id="id" type="hidden"/>

     <div class="layui-form-item">

-        <label class="layui-form-label">角色</label>

+        <label class="layui-form-label">功能名称</label>

         <div class="layui-input-block">

-            <select name="rolename">

-                <option value="0">管理员</option>

-                <option value="1">超级管理员</option>

-                <option value="2">纠错员</option>

-                <option value="3">采购员</option>

-                <option value="4">推销员</option>

-                <option value="5">运营人员</option>

-                <option value="6">编辑</option>

-            </select>

+            <input name="name" placeholder="请输入功能名称" type="text" class="layui-input" maxlength="20"

+                   lay-verify="required|name" required/>

         </div>

     </div>

     <div class="layui-form-item">

-        <label class="layui-form-label">权限范围</label>

+        <label class="layui-form-label">路径</label>

         <div class="layui-input-block">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="内容系统">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="社区系统">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="用户">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="角色">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="评论审核">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="发货">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="采购">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="系统设置">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="发邮件">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="发短信">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="审核">

-            <input type="checkbox" name="limits[]" lay-skin="primary" title="删库跑路">

+            <input name="menuUrl" placeholder="请输入路径,父节点默认为 # " type="text" class="layui-input" maxlength="60" value="#" lay-verify="required" required/>

         </div>

     </div>

     <div class="layui-form-item">

-        <label class="layui-form-label">具体描述</label>

+        <label class="layui-form-label">节点</label>

         <div class="layui-input-block">

-            <textarea type="text" name="descr" lay-verify="required" autocomplete="off"

-                      class="layui-textarea"></textarea>

+            <input type="radio" name="isLeaf" value="0" title="父" checked/>

         </div>

     </div>

-    <div class="layui-form-item layui-hide">

-        <button class="layui-btn" lay-submit lay-filter="LAY-user-role-submit" id="LAY-user-role-submit">提交</button>

+    <div class="layui-form-item">

+        <label class="layui-form-label">序号</label>

+        <div class="layui-input-block">

+            <input name="orderNum" placeholder="请输入序号" type="text" class="layui-input" />

+        </div>

     </div>

-</div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">图标</label>

+        <div class="layui-input-block">

+            <input name="menuIcon" placeholder="请输入图标 例:layui-icon-xx " type="text" class="layui-input" />

+        </div>

+    </div>

+

+    <div class="layui-form-item model-form-footer">

+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>

+        <button class="layui-btn" lay-filter="form-submit" lay-submit  id="submitbtn">保存</button>

+    </div>

+</form>

+

+<script>

+    layui.use(['layer', 'admin', 'form', 'formSelects'], function () {

+        var layer = layui.layer;

+        var admin = layui.admin;

+        var form = layui.form;

+        var formSelects = layui.formSelects;

+        form.render('radio');

+        form.verify({

+            "name": function (e) {

+                var msg = "";

+                $.ajax({

+                    type: "GET",

+                    url: '/function/checkname',

+                    async: false,

+                    data: {

+                        name: e,

+                        id: $("#id").val()

+                    },

+                    success: function (result) {

+                        if (result.code != 200) {

+                            msg = result.msg;

+                        }

+                    },

+                    error: function (error) {

+                        msg = "请求服务器校验账号失败";

+                    }

+                });

+            }

+        });

+

+        var url = '/function/add';

+        // 回显user数据

+        var func = admin.getTempData('t_func');

+        if (func) {

+            $('input[name="id"]').attr('readonly', 'readonly');

+            form.val('form', func);

+        }

+        // 表单提交事件

+        form.on('submit(form-submit)', function (data) {

+            layer.load(2);

+            let token = $("meta[name='_csrf_token']").attr("value");

+            debugger

+            $.ajax({

+                type : "POST",

+                dataType : "json",

+                url : url,

+                headers: {

+                    'Accept': 'application/json',

+                    'Content-Type': 'application/json',

+                    'X-CSRF-TOKEN':token,

+                },

+                data : JSON.stringify(data.field),

+                success : function(result) {

+                    layer.closeAll('loading');

+                    if (result.code == 200) {

+                        layer.msg(result.msg, {icon: 1});

+                        admin.finishPopupCenter();

+                    } else if (result.code == 401) {

+                        layer.msg(result.msg, {icon: 2, time: 1500}, function () {

+                            location.replace('/login');

+                        }, 1000);

+                        return;

+                    } else {

+                        console.log('err:' + result.code);

+                        layer.msg(result.msg, {icon: 2});

+                    }

+                },

+                error : function() {

+                    layer.closeAll('loading');

+                    layer.msg("请求服务器失败!", {icon: 2});

+                }

+            });

+            return false;

+        });

+    });

+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/function/index.html b/src/main/resources/templates/system/function/index.html
index afcda4c..245090c 100755
--- a/src/main/resources/templates/system/function/index.html
+++ b/src/main/resources/templates/system/function/index.html
@@ -10,28 +10,19 @@
         <div class="layui-form toolbar">

             搜索:

             <input id="search-value" class="layui-input search-input" type="text" placeholder="输入功能名称"/>&emsp;

-            <button id="btn-search" class="layui-btn icon-btn" data-type="search"><i class="layui-icon">&#xe615;</i>搜索</button>

-            <button id="btn-add" class="layui-btn icon-btn" data-type="add" ><i class="layui-icon"></i>添加

+            <button id="btn-search" class="layui-btn icon-btn" data-type="search"><i class="layui-icon">&#xe615;</i>搜索

             </button>

+            <button id="btn-add" class="layui-btn icon-btn" data-type="add"><i class="layui-icon"></i>添加父功能</button>

         </div>

-        <table class="layui-table" id="table"></table>

+        <table class="layui-table" id="table" lay-filter="table"></table>

     </div>

 </div>

 

-<!-- 表格操作列 -->

-<script type="text/html" id="table-bar">

-    <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>

-    <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-set-sm"></i>维护资源</a>

-    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>

-</script>

-

 <script>

     layui.use(['form', 'table', 'layer', 'admin', 'element'], function () {

-        var form = layui.form;

-        var table = layui.table;

-        var layer = layui.layer;

-        var admin = layui.admin;

-        var element = layui.element;

+        let form = layui.form;

+        let table = layui.table;

+        let admin = layui.admin;

 

         form.render('select');

 

@@ -42,7 +33,7 @@
             page: true,

             cols: [

                 [

-                    {field: 'id', title: '功能ID', fixed: 'left', sort: true},

+                    {field: 'id', title: '功能ID', width: 80,fixed: 'left', sort: true},

                     {field: 'name', title: '功能名称', sort: true},

                     {

                         field: 'isLeaf', title: '节点', sort: true, width: 80, align: 'center', templet: function (item) {

@@ -56,115 +47,129 @@
                         }

                     },

                     {field: 'menuUrl', title: '路径'},

-                    {field: 'orderNum', sort: true, title: '序号'},

-                    {field: 'menuIcon', title: '图标',align: 'center', templet: function (item) {

-                            return '<i class="layui-icon '+item.menuIcon+'"></i> '

+                    {field: 'orderNum', sort: true, width: 80,title: '序号'},

+                    {

+                        field: 'menuIcon', title: '图标', width: 80,align: 'center', templet: function (item) {

+                            return '<i class="layui-icon ' + item.menuIcon + '"></i> '

                         }

                     },

-                    {field:'id',align: 'center', toolbar: '#table-bar', title: '操作', fixed: 'right'}

+                    {

+                        field: 'id', align: 'center', title: '操作', fixed: 'right', templet: function (item) {

+                            if (item.isLeaf == 0) {

+                                return ' <a class="layui-btn  layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a> ' +

+                                    ' <a class="layui-btn layui-btn-normal  layui-btn-xs" lay-event="addsub"><i class="layui-icon layui-icon-set-sm"></i>添加子功能</a> ' +

+                                    ' <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>'

+                            } else {

+                                return ' <a class="layui-btn  layui-btn-xs" lay-event="editsub"><i class="layui-icon layui-icon-edit"></i>编辑</a> ' +

+                                    ' <a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="addres"><i class="layui-icon layui-icon-set-sm"></i>添加资源</a> ' +

+                                    ' <a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="listres"><i class="layui-icon layui-icon-set-sm"></i>维护资源</a> ' +

+                                    ' <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>'

+                            }

+                        }

+                    }

                 ]

             ]

         });

         // 搜索按钮点击事件

         $('#btn-search').click(function () {

-            var key = $('#search-value').val();

+            let key = $('#search-value').val();

             table.reload('table', {where: {searchkey: key}, page: {curr: 1}});

         });

         $('#btn-add').click(function () {

-            layer.open({

-                type: 1

-                ,title: '添加功能'

-                ,content: 'form.html'

-                ,maxmin: true

-                ,area: ['500px', '450px']

-                ,btn: ['确定', '取消']

-                ,yes: function(index, layero){

-                    var iframeWindow = window['layui-layer-iframe'+ index]

-                        ,submitID = 'LAY-user-front-submit'

-                        ,submit = layero.find('iframe').contents().find('#'+ submitID);

-

-                    //监听提交

-                    iframeWindow.layui.form.on('submit('+ submitID +')', function(data){

-                        var field = data.field; //获取提交的字段

-                        //提交 Ajax 成功后,静态更新表格中的数据

-                        //$.ajax({});

-                        table.reload('table');

-                        layer.close(index); //关闭弹层

-                    });

-

-                    submit.trigger('click');

-                }

-            });

+            showModel();

         });

-        // 显示表单弹窗

-        var showEditModel = function (data) {

-            var title = data ? '修改用户' : '添加用户';

-            admin.putTempData('t_user', data);

+        let showModel = function (data) {

+            let title = data ? '编辑父功能' : '添加父功能';

+            admin.putTempData('t_func', data);

             admin.popupCenter({

                 title: title,

-                path: '/operator/load4add',

+                path: '/function/loadadd',

                 finish: function () {

-                    table.reload('oper-table', {});

+                    table.reload('table', {});

+                }

+            });

+        };

+        let showModelSub = function (data,parentid) {

+            let title = data ? '编辑子功能' : '添加子功能';

+            admin.putTempData('parentId', parentid);

+            admin.putTempData('t_func', data);

+            admin.popupCenter({

+                title: title,

+                path: '/function/loadsubadd',

+                finish: function () {

+                    table.reload('table', {});

                 }

             });

         };

 

-        // 工具条点击事件

-        table.on('tool(user-table)', function (obj) {

-            console.log(obj);

-            var data = obj.data;

-            var layEvent = obj.event;

-

-            if (layEvent === 'edit') { // 修改

-                showEditModel(data);

-            } else if (layEvent === 'reset') { // 重置密码

-                layer.confirm('确定重置此用户的密码吗?', function (i) {

-                    layer.close(i);

-                    layer.load(2);

-                    admin.go('/system/user/restPsw', {

-                        userId: obj.data.userId

-                    }, function (data) {

-                        console.log(data.code);

-                        layer.closeAll('loading');

-                        if (data.code == 200) {

-                            layer.msg(data.msg, {icon: 1});

-                        } else if (data.code == 401) {

-                            layer.msg(data.msg, {icon: 2, time: 1500}, function () {

-                                location.replace('/login');

-                            }, 1000);

-                            return;

-                        }

-                        else {

-                            layer.msg(data.msg, {icon: 2});

-                        }

-                    });

-                });

-            }

-        });

-

-        // 修改user状态

-        form.on('switch(user-tpl-state)', function (obj) {

-            layer.load(2);

-            admin.go('/system/user/updateState', {

-                userId: obj.elem.value,

-                state: obj.elem.checked ? 0 : 1

-            }, function (data) {

-                layer.closeAll('loading');

-                if (data.code == 200) {

-                    layer.msg(data.msg, {icon: 1});

-                    //table.reload('table-user', {});

-                } else if (data.code == 401) {

-                    layer.msg(data.msg, {icon: 2, time: 1500}, function () {

-                        location.replace('/login');

-                    }, 1000);

-                    return;

-                } else {

-                    layer.msg(data.msg, {icon: 2});

-                    $(obj.elem).prop('checked', !obj.elem.checked);

-                    form.render('checkbox');

+        let showResModel = function (functionid) {

+            let title = '维护资源';

+            admin.putTempData('functionid', functionid);

+            admin.popupCenter({

+                title: title,

+                area:'70%',

+                path: '/function/loadres?functionid='+functionid

+            });

+        };

+        let showAddResModelSub = function (functionid) {

+            let title = '添加资源';

+            admin.putTempData('functionid', functionid);

+            admin.popupCenter({

+                title: title,

+                path: '/function/loadresadd',

+                finish: function () {

+                    table.reload('table', {});

                 }

             });

+        };

+        // 工具条点击事件

+        table.on('tool(table)', function (obj) {

+            let data = obj.data;

+            let layEvent = obj.event;

+            console.log(data);

+            if (layEvent === 'edit') {

+                showModel(data);

+            } else if (layEvent === 'addsub') {

+                showModelSub(null,data.id);

+            } else if (layEvent === 'editsub') {

+                showModelSub(data,data.parentId);

+            } else if (layEvent === 'del') {

+                showDelete(data);

+            } else if(layEvent === 'listres'){

+                showResModel(data.id);

+            } else if(layEvent === 'addres'){

+                showAddResModelSub(data.id);

+            }

         });

-

+        let showDelete = function (data) {

+            layer.confirm('确定删除吗,该功能下的子功能、资源、角色分配的该功能都将被删除?', function (i) {

+                layer.close(i);

+                layer.load(2);

+                let token = $("meta[name='_csrf_token']").attr("value");

+                admin.go('/function/delfunc', {

+                    funcid: data.id,

+                    _csrf:token

+                }, function (data) {

+                    console.log(data.code);

+                    layer.closeAll('loading');

+                    if (data.code == 200) {

+                        layer.msg(data.msg, {icon: 1});

+                    } else if (data.code == 401) {

+                        layer.msg(data.msg, {icon: 2, time: 1500}, function () {

+                            location.replace('/login');

+                        }, 1000);

+                        return;

+                    }

+                    else {

+                        layer.msg(data.msg, {icon: 2});

+                    }

+                    table.reload('table', {});

+                },function(ret){

+                    console.log(ret);

+                    layer.closeAll('loading');

+                    layer.msg('请求失败了,请稍后再试', {icon: 2});

+                });

+            });

+        }

     });

 </script>

diff --git a/src/main/resources/templates/system/function/resform.html b/src/main/resources/templates/system/function/resform.html
new file mode 100755
index 0000000..78f7747
--- /dev/null
+++ b/src/main/resources/templates/system/function/resform.html
@@ -0,0 +1,94 @@
+<!-- operator表单弹窗 -->

+<form id="resform" lay-filter="resform" class="layui-form model-form">

+    <input name="id" id="id" type="hidden"/>

+    <div class="layui-form-item">

+        <label class="layui-form-label">资源名称</label>

+        <div class="layui-input-block">

+            <input name="name" placeholder="请输入资源名称" type="text" class="layui-input" maxlength="60"

+                   lay-verify="required|name" required/>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">路径</label>

+        <div class="layui-input-block">

+            <input name="uri" placeholder="请输入资源路径 " type="text" class="layui-input" maxlength="100"

+                   lay-verify="required" required/>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">所属功能</label>

+        <div class="layui-input-block">

+            <select name="functionId" id="functionId" lay-verify="required">

+                <option th:each="func : ${list}" th:value="${func.id}">[[${func.name}]]</option>

+            </select>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">代码</label>

+        <div class="layui-input-block">

+            <input name="code" placeholder="请输入代码" type="text" class="layui-input"/>

+        </div>

+    </div>

+    <div class="layui-form-item model-form-footer">

+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>

+        <button class="layui-btn" lay-filter="resform-submit" lay-submit id="submitbtn">保存</button>

+    </div>

+</form>

+

+<script>

+    layui.use(['layer', 'admin', 'form', 'formSelects'], function () {

+        var layer = layui.layer;

+        var admin = layui.admin;

+        var form = layui.form;

+        form.render('select');

+        form.render('radio');

+        var url = '/function/addres';

+        // 回显user数据

+        var func = admin.getTempData('t_res');

+        if (func) {

+            $('input[name="id"]').attr('readonly', 'readonly');

+            form.val('resform', func);

+        }

+        let functionid = admin.getTempData("functionid");

+        if (functionid) {

+            form.val('resform', {"functionId": functionid});

+        }

+        // 表单提交事件

+        form.on('submit(resform-submit)', function (data) {

+            layer.load(2);

+            let token = $("meta[name='_csrf_token']").attr("value");

+            debugger

+            $.ajax({

+                type: "POST",

+                dataType: "json",

+                url: url,

+                headers: {

+                    'Accept': 'application/json',

+                    'Content-Type': 'application/json',

+                    'X-CSRF-TOKEN': token,

+                },

+                data: JSON.stringify(data.field),

+                success: function (result) {

+                    layer.closeAll('loading');

+                    if (result.code == 200) {

+                        layer.msg(result.msg, {icon: 1});

+                        admin.finishPopupCenter();

+                    } else if (result.code == 401) {

+                        layer.msg(result.msg, {icon: 2, time: 1500}, function () {

+                            location.replace('/login');

+                        }, 1000);

+                        return;

+                    } else {

+                        console.log('err:' + result.code);

+                        layer.msg(result.msg, {icon: 2});

+                    }

+                },

+                error: function () {

+                    layer.closeAll('loading');

+                    layer.msg("请求服务器失败!", {icon: 2});

+                }

+            });

+            return false;

+        });

+    });

+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/function/reslist.html b/src/main/resources/templates/system/function/reslist.html
new file mode 100755
index 0000000..d95cbfe
--- /dev/null
+++ b/src/main/resources/templates/system/function/reslist.html
@@ -0,0 +1,90 @@
+<div style="padding:20px;">

+    <table class="layui-table" id="restable" lay-filter="restable">

+    </table>

+    <input type="hidden" id="functionid" th:value="${function.id}">

+    <input type="hidden" id="functionname" th:value="${function.name}">

+</div>

+<script>

+    layui.use(['form', 'table', 'layer', 'admin', 'element'], function () {

+        let form = layui.form;

+        let admin = layui.admin;

+        form.render('select');

+        let table = layui.table;

+        let func = admin.getTempData('functionid');

+        table.render({

+            elem: '#restable',

+            url: '/function/reslist?functionid=' + func,

+            cols: [

+                [

+                    {field: 'id', title: '资源ID', width: 80, fixed: 'left', sort: true},

+                    {field: 'name', title: '资源名称', sort: true},

+                    {

+                        field: 'functionId', title: '所属功能', sort: true, align: 'center', templet: function (item) {

+                            return $("#functionname").val();

+                        }

+                    },

+                    {field: 'uri', title: '路径'},

+                    {field: 'code', sort: true, width: 80, title: '代码'},

+                    {

+                        field: 'id', align: 'center', title: '操作',  templet: function (item) {

+                            return '<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>'

+                        }

+                    }

+                ]

+            ]

+        });

+        // 工具条点击事件

+        table.on('tool(restable)', function (obj) {

+            let data = obj.data;

+            let layEvent = obj.event;

+            console.log(data);

+            if (layEvent === 'edit') {

+                showAddResModelSub(data);

+            } else if (layEvent === 'del') {

+                showDelete(data);

+            }

+        });

+        let showAddResModelSub = function (data) {

+            let title = '编辑资源';

+            admin.putTempData('functionid', $("#functionid").val());

+            admin.putTempData('t_data',data);

+            admin.popupCenter({

+                title: title,

+                path: '/function/loadresadd',

+                finish: function () {

+                    table.reload('table', {});

+                }

+            });

+        };

+        let showDelete = function (data) {

+            layer.confirm('确定删除吗?', function (i) {

+                layer.close(i);

+                layer.load(2);

+                let token = $("meta[name='_csrf_token']").attr("value");

+                admin.go('/function/delres', {

+                    resid: data.id,

+                    _csrf:token

+                }, function (data) {

+                    console.log(data.code);

+                    layer.closeAll('loading');

+                    if (data.code == 200) {

+                        layer.msg(data.msg, {icon: 1});

+                    } else if (data.code == 401) {

+                        layer.msg(data.msg, {icon: 2, time: 1500}, function () {

+                            location.replace('/login');

+                        }, 1000);

+                        return;

+                    }

+                    else {

+                        layer.msg(data.msg, {icon: 2});

+                    }

+                    table.reload('restable', {});

+                },function(ret){

+                    console.log(ret);

+                    layer.closeAll('loading');

+                    layer.msg('请求失败了,请稍后再试', {icon: 2});

+                });

+            });

+        }

+    });

+</script>

diff --git a/src/main/resources/templates/system/function/subform.html b/src/main/resources/templates/system/function/subform.html
new file mode 100755
index 0000000..def716f
--- /dev/null
+++ b/src/main/resources/templates/system/function/subform.html
@@ -0,0 +1,106 @@
+<!-- operator表单弹窗 -->

+<form id="form" lay-filter="subform" class="layui-form model-form">

+    <input name="id" id="id" type="hidden"/>

+    <div class="layui-form-item">

+        <label class="layui-form-label">功能名称</label>

+        <div class="layui-input-block">

+            <input name="name" placeholder="请输入功能名称" type="text" class="layui-input" maxlength="20"

+                   lay-verify="required|name" required/>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">路径</label>

+        <div class="layui-input-block">

+            <input name="menuUrl" placeholder="请输入路径,父节点默认为 # " type="text" class="layui-input" maxlength="60" lay-verify="required" required/>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">父功能</label>

+        <div class="layui-input-block">

+            <select name="parentId" id="parentId" lay-verify="required">

+                <option th:each="func : ${list}" th:value="${func.id}">[[${func.name}]]</option>

+            </select>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">节点</label>

+        <div class="layui-input-block">

+            <input type="radio" name="isLeaf" value="1" title="子" checked/>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">序号</label>

+        <div class="layui-input-block">

+            <input name="orderNum" placeholder="请输入序号" type="text" class="layui-input" />

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">图标</label>

+        <div class="layui-input-block">

+            <input name="menuIcon" placeholder="请输入图标 例:layui-icon-xx " type="text" class="layui-input" />

+        </div>

+    </div>

+

+    <div class="layui-form-item model-form-footer">

+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>

+        <button class="layui-btn" lay-filter="subform-submit" lay-submit  id="submitbtn">保存</button>

+    </div>

+</form>

+

+<script>

+    layui.use(['layer', 'admin', 'form', 'formSelects'], function () {

+        var layer = layui.layer;

+        var admin = layui.admin;

+        var form = layui.form;

+        form.render('select');

+        form.render('radio');

+        var url = '/function/add';

+        // 回显user数据

+        var func = admin.getTempData('t_func');

+        if (func) {

+            $('input[name="id"]').attr('readonly', 'readonly');

+            form.val('subform', func);

+        }

+        let parentId = admin.getTempData("parentId");

+        if(parentId){

+            form.val('form', {"parentId":parentId});

+        }

+        // 表单提交事件

+        form.on('submit(subform-submit)', function (data) {

+            layer.load(2);

+            let token = $("meta[name='_csrf_token']").attr("value");

+            debugger

+            $.ajax({

+                type : "POST",

+                dataType : "json",

+                url : url,

+                headers: {

+                    'Accept': 'application/json',

+                    'Content-Type': 'application/json',

+                    'X-CSRF-TOKEN':token,

+                },

+                data : JSON.stringify(data.field),

+                success : function(result) {

+                    layer.closeAll('loading');

+                    if (result.code == 200) {

+                        layer.msg(result.msg, {icon: 1});

+                        admin.finishPopupCenter();

+                    } else if (result.code == 401) {

+                        layer.msg(result.msg, {icon: 2, time: 1500}, function () {

+                            location.replace('/login');

+                        }, 1000);

+                        return;

+                    } else {

+                        console.log('err:' + result.code);

+                        layer.msg(result.msg, {icon: 2});

+                    }

+                },

+                error : function() {

+                    layer.closeAll('loading');

+                    layer.msg("请求服务器失败!", {icon: 2});

+                }

+            });

+            return false;

+        });

+    });

+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/operator/index.html b/src/main/resources/templates/system/operator/index.html
index 1f6dad4..14861c7 100644
--- a/src/main/resources/templates/system/operator/index.html
+++ b/src/main/resources/templates/system/operator/index.html
@@ -110,7 +110,6 @@
             });
         };
 
-
         // 工具条点击事件
         table.on('tool(user-table)', function (obj) {
             console.log(obj);
diff --git a/src/main/resources/templates/system/role/form.html b/src/main/resources/templates/system/role/form.html
new file mode 100755
index 0000000..0769c8c
--- /dev/null
+++ b/src/main/resources/templates/system/role/form.html
@@ -0,0 +1,74 @@
+<!-- operator表单弹窗 -->

+<form id="form" lay-filter="form" class="layui-form model-form">

+    <input name="roleId" id="roleId" type="hidden"/>

+    <div class="layui-form-item">

+        <label class="layui-form-label">角色名称</label>

+        <div class="layui-input-block">

+            <input name="roleName" placeholder="请输入角色名称" type="text" class="layui-input" maxlength="20"

+                   lay-verify="required|roleName" required/>

+        </div>

+    </div>

+    <div class="layui-form-item">

+        <label class="layui-form-label">角色描述</label>

+        <div class="layui-input-block">

+            <textarea name="roleDesc" placeholder="请输入描述" class="layui-textarea"></textarea>

+        </div>

+    </div>

+

+    <div class="layui-form-item model-form-footer">

+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>

+        <button class="layui-btn" lay-filter="form-submit" lay-submit  id="submitbtn">保存</button>

+    </div>

+</form>

+

+<script>

+    layui.use(['layer', 'admin', 'form', 'formSelects'], function () {

+        var layer = layui.layer;

+        var admin = layui.admin;

+        var form = layui.form;

+        var url = '/role/add';

+        // 回显user数据

+        var func = admin.getTempData('t_func');

+        if (func) {

+            $('input[name="roleId"]').attr('readonly', 'readonly');

+            form.val('form', func);

+        }

+        // 表单提交事件

+        form.on('submit(form-submit)', function (data) {

+            layer.load(2);

+            let token = $("meta[name='_csrf_token']").attr("value");

+            debugger

+            $.ajax({

+                type : "POST",

+                dataType : "json",

+                url : url,

+                headers: {

+                    'Accept': 'application/json',

+                    'Content-Type': 'application/json',

+                    'X-CSRF-TOKEN':token,

+                },

+                data : JSON.stringify(data.field),

+                success : function(result) {

+                    layer.closeAll('loading');

+                    if (result.code == 200) {

+                        layer.msg(result.msg, {icon: 1});

+                        admin.finishPopupCenter();

+                    } else if (result.code == 401) {

+                        layer.msg(result.msg, {icon: 2, time: 1500}, function () {

+                            location.replace('/login');

+                        }, 1000);

+                        return;

+                    } else {

+                        console.log('err:' + result.code);

+                        layer.msg(result.msg, {icon: 2});

+                    }

+                },

+                error : function() {

+                    layer.closeAll('loading');

+                    layer.msg("请求服务器失败!", {icon: 2});

+                }

+            });

+            return false;

+        });

+    });

+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/role/func.html b/src/main/resources/templates/system/role/func.html
new file mode 100755
index 0000000..d838bb5
--- /dev/null
+++ b/src/main/resources/templates/system/role/func.html
@@ -0,0 +1,88 @@
+<div style="padding: 0 20px">

+    <div class="layui-form-item">

+        <ul id="funclist" class="ztree"></ul>

+    </div>

+    <div class="layui-form-item model-form-footer">

+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>

+        <button class="layui-btn" lay-filter="form-submit" id="submitbtn">保存</button>

+    </div>

+</div>

+<script>

+    layui.use(['layer', 'admin', 'form', 'formSelects'], function () {

+        var layer = layui.layer;

+        var admin = layui.admin;

+        var form = layui.form;

+        var func = admin.getTempData('roleId');

+        let initTree = function (nodes) {

+            let menuSetting = {

+                view: {

+                    dblClickExpand: true,

+                    showLine: true,

+                    showIcon: false

+                },

+                check: {

+                    enable: true,

+                },

+                data: {

+                    simpleData: {

+                        enable: true

+                    }

+                }

+            };

+            $.fn.zTree.init($("#funclist"), menuSetting, nodes);

+        }

+        admin.dgo('/role/func', {

+            roleId: func,

+        }, function (data) {

+            layer.closeAll('loading');

+            if (data.code == 200) {

+                initTree(data.node);

+            } else if (data.code == 401) {

+                layer.msg(data.msg, {icon: 2, time: 1500}, function () {

+                    location.replace('/login');

+                }, 1000);

+                return;

+            } else {

+                layer.msg(data.msg, {icon: 2});

+            }

+        }, function (ret) {

+            layer.closeAll('loading');

+            layer.msg('请求失败了,请稍后再试', {icon: 2});

+        });

+        $("#submitbtn").on('click', function (e) {

+            let ids = [];

+            let treeObj = $.fn.zTree.getZTreeObj("funclist");

+            let nodes = treeObj.getCheckedNodes(true);

+            for (let i = 0; i < nodes.length; i++) {

+                ids.push(nodes[i].id);//存功能ID

+            }

+            if (ids.length < 1) {

+                return;

+            }

+            let idStr = ids.toString();

+            let token = $("meta[name='_csrf_token']").attr("value");

+            admin.go('/role/addfunc', {

+                roleId: func,

+                funcs: idStr,

+                _csrf: token,

+            }, function (data) {

+                layer.closeAll('loading');

+                if (data.code == 200) {

+                    layer.msg(data.msg, {icon: 1});

+                    admin.finishPopupCenter();

+                } else if (data.code == 401) {

+                    layer.msg(data.msg, {icon: 2, time: 1500}, function () {

+                        location.replace('/login');

+                    }, 1000);

+                    return;

+                } else {

+                    layer.msg(data.msg, {icon: 2});

+                }

+            }, function (ret) {

+                console.log(ret);

+                layer.closeAll('loading');

+                layer.msg('请求失败了,请稍后再试', {icon: 2});

+            });

+        })

+    });

+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/role/index.html b/src/main/resources/templates/system/role/index.html
index df1c415..c96d529 100644
--- a/src/main/resources/templates/system/role/index.html
+++ b/src/main/resources/templates/system/role/index.html
@@ -7,6 +7,111 @@
         </span>
     </div>
     <div class="layui-card-body">
-        <table class="layui-table" id="user-table" lay-filter="user-table"></table>
+        <div class="layui-form toolbar">
+            搜索:
+            <input id="search-value" class="layui-input search-input" type="text" placeholder="输入角色名称"/>&emsp;
+            <button id="btn-search" class="layui-btn icon-btn" data-type="search"><i class="layui-icon">&#xe615;</i>搜索
+            </button>
+            <button id="btn-add" class="layui-btn icon-btn" data-type="add"><i class="layui-icon"></i>添加角色</button>
+        </div>
+        <table class="layui-table" id="roletable" lay-filter="roletable"></table>
     </div>
-</div>
\ No newline at end of file
+</div>
+<script>
+    layui.use(['form', 'table', 'layer', 'admin', 'element'], function () {
+        let form = layui.form;
+        let table = layui.table;
+        let admin = layui.admin;
+
+        form.render('select');
+
+        // 渲染表格
+        table.render({
+            elem: '#roletable',
+            url: '/role/list',
+            page: true,
+            cols: [
+                [
+                    {field: 'roleName', title: '角色名称', fixed: 'left', sort: true},
+                    {field: 'roleDesc', title: '描述'},
+                    {
+                        field: 'roleId', align: 'center', title: '操作', fixed: 'right', templet: function (item) {
+                            return ' <a class="layui-btn  layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a> ' +
+                                ' <a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="addfunc"><i class="layui-icon layui-icon-set-sm"></i>分配功能</a> ' +
+                                ' <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>'
+                        }
+                    }
+                ]
+            ]
+        });
+        // 搜索按钮点击事件
+        $('#btn-search').click(function () {
+            let key = $('#search-value').val();
+            table.reload('roletable', {where: {searchkey: key}, page: {curr: 1}});
+        });
+        $('#btn-add').click(function () {
+            showModel();
+        });
+        let showModel = function (data) {
+            let title = data ? '编辑角色' : '添加角色';
+            admin.putTempData('t_func', data);
+            admin.popupCenter({
+                title: title,
+                path: '/role/loadadd',
+                finish: function () {
+                    table.reload('roletable', {});
+                }
+            });
+        };
+        let showFuncModel = function (data) {
+            let title = '分配功能';
+            admin.putTempData('roleId', data.roleId);
+            admin.popupCenter({
+                title: title,
+                path: '/role/loadfunc'
+            });
+        };
+        // 工具条点击事件
+        table.on('tool(roletable)', function (obj) {
+            let data = obj.data;
+            let layEvent = obj.event;
+            console.log(data);
+            if (layEvent === 'edit') {
+                showModel(data);
+            } else if (layEvent === 'addfunc') {
+                showFuncModel(data);
+            } else if (layEvent === 'del') {
+                showDelete(data);
+            }
+        });
+        let showDelete = function (data) {
+            layer.confirm('确定删除吗,该功能下的子功能、资源、角色分配的该功能都将被删除?', function (i) {
+                layer.close(i);
+                layer.load(2);
+                let token = $("meta[name='_csrf_token']").attr("value");
+                admin.go('/role/del', {
+                    funcid: data.id,
+                    _csrf: token
+                }, function (data) {
+                    console.log(data.code);
+                    layer.closeAll('loading');
+                    if (data.code == 200) {
+                        layer.msg(data.msg, {icon: 1});
+                    } else if (data.code == 401) {
+                        layer.msg(data.msg, {icon: 2, time: 1500}, function () {
+                            location.replace('/login');
+                        }, 1000);
+                        return;
+                    } else {
+                        layer.msg(data.msg, {icon: 2});
+                    }
+                    table.reload('table', {});
+                }, function (ret) {
+                    console.log(ret);
+                    layer.closeAll('loading');
+                    layer.msg('请求失败了,请稍后再试', {icon: 2});
+                });
+            });
+        }
+    });
+</script>
\ No newline at end of file