Parcourir la source

rbac 页面接口开发中

reghao il y a 4 ans
Parent
commit
1bac4a8751
21 fichiers modifiés avec 162 ajouts et 64 suppressions
  1. 10 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/db/UserCrud.java
  2. 2 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/entity/Menu.java
  3. 1 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/entity/Role.java
  4. 2 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/entity/User.java
  5. 10 20
      dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/service/UserService.java
  6. 19 3
      dmaster/src/main/java/cn/reghao/autodop/dmaster/utils/WebBody.java
  7. 16 3
      dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/ResourcePageController.java
  8. 22 5
      dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/RoleController.java
  9. 12 6
      dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/RolePageController.java
  10. 8 11
      dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/UserController.java
  11. 4 4
      dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/UserPageController.java
  12. 0 2
      dmaster/src/main/resources/application.yml
  13. BIN
      dmaster/src/main/resources/static/imgs/favicon.ico
  14. BIN
      dmaster/src/main/resources/static/imgs/mo-favicon.ico
  15. 1 1
      dmaster/src/main/resources/templates/common/template.html
  16. 1 1
      dmaster/src/main/resources/templates/login.html
  17. 6 2
      dmaster/src/main/resources/templates/system/menu/index.html
  18. 38 0
      dmaster/src/main/resources/templates/system/menu/roleList.html
  19. 4 0
      dmaster/src/main/resources/templates/system/role/auth.html
  20. 4 5
      dmaster/src/main/resources/templates/system/role/index.html
  21. 2 0
      dmaster/src/main/resources/templates/system/user/index.html

+ 10 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/db/UserCrud.java

@@ -32,4 +32,14 @@ public class UserCrud {
 
         return null;
     }
+
+    public List<User> findUsers(String role) {
+        Specification<User> spec = ((root, query, criteriaBuilder) -> {
+            Join<User, Role> innerJoin = root.join("", JoinType.INNER);
+            Predicate predicate = criteriaBuilder.equal(innerJoin.get(""), role);
+            return criteriaBuilder.and(predicate);
+        });
+
+        return userRepository.findAll(spec);
+    }
 }

+ 2 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/entity/Menu.java

@@ -30,6 +30,8 @@ public class Menu extends BaseEntity<Integer> {
     // Menu 类型
     private String type;
     private String icon;
+    @Transient
+    private String remark;
     // 可访问资源的角色,一个资源可被多个角色访问
     @ManyToMany(mappedBy = "menus")
     private Set<Role> roles;

+ 1 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/entity/Role.java

@@ -16,7 +16,7 @@ import java.util.Set;
  */
 @NoArgsConstructor
 @Data
-@EqualsAndHashCode(callSuper = false, exclude = {"menus"})
+@EqualsAndHashCode(callSuper = false, exclude = {"remark", "menus"})
 @ToString(exclude = {"menus"})
 @Entity
 public class Role extends BaseEntity<Integer> {

+ 2 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/entity/User.java

@@ -1,6 +1,7 @@
 package cn.reghao.autodop.dmaster.auth.entity;
 
 import cn.reghao.autodop.common.orm.BaseEntity;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
@@ -26,6 +27,7 @@ public class User extends BaseEntity<Integer> implements UserDetails {
     @Column(nullable = false, unique = true)
     private String username;
     @Column(nullable = false)
+    @JsonIgnore
     private String password;
     @Column(nullable = false)
     private String salt;

+ 10 - 20
dmaster/src/main/java/cn/reghao/autodop/dmaster/auth/service/UserService.java

@@ -18,6 +18,7 @@ import org.springframework.stereotype.Service;
 
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -73,17 +74,12 @@ public class UserService {
         userRepository.save(user);
     }
 
-    public void modifyUserRoles(int userId, Set<Integer> roleIds) {
-        List<Integer> list = new ArrayList<>(roleIds);
-        // 修改后用户的角色
-        List<Role> newRoles = roleCrud.findByRoleIds(list);
-
-        // 用户当前的角色
-        User user = userRepository.findById(userId);
-        List<String> roles = user.getAuthorities().stream()
+    public void modifyUserRoles(User user, Set<Role> roles) {
+        // 用户当前拥有的角色
+        List<String> roleList = user.getAuthorities().stream()
                 .map(GrantedAuthority::getAuthority).collect(Collectors.toList());
-        if (roles.isEmpty()) {
-            Set<GrantedAuthorityImpl> authorities = newRoles.stream()
+        if (roleList.isEmpty()) {
+            Set<GrantedAuthorityImpl> authorities = roles.stream()
                     .map(role -> new GrantedAuthorityImpl(role.getTitle()))
                     .collect(Collectors.toSet());
             user.setAuthorities(authorities);
@@ -91,22 +87,16 @@ public class UserService {
             return;
         }
 
-        List<Role> currentRoles = getUserRoles(userId);
-        if (currentRoles.isEmpty()) {
-            List<GrantedAuthorityImpl> authorities = newRoles.stream()
-                    .map(role -> new GrantedAuthorityImpl(role.getTitle()))
-                    .collect(Collectors.toList());
-        }
-
+        List<Role> currentRoles = getUserRoles(user.getId());
         List<Role> tmp = new ArrayList<>(currentRoles);
         tmp.forEach(role -> {
-            if (newRoles.remove(role)) {
+            if (roles.remove(role)) {
                 currentRoles.remove(role);
             }
         });
 
-        if (!newRoles.isEmpty()) {
-            Set<GrantedAuthorityImpl> authorities = newRoles.stream()
+        if (!roles.isEmpty()) {
+            Set<GrantedAuthorityImpl> authorities = roles.stream()
                     .map(role -> new GrantedAuthorityImpl(role.getTitle()))
                     .collect(Collectors.toSet());
             user.setAuthorities(authorities);

+ 19 - 3
dmaster/src/main/java/cn/reghao/autodop/dmaster/utils/WebBody.java

@@ -3,9 +3,15 @@ package cn.reghao.autodop.dmaster.utils;
 import cn.reghao.autodop.common.utils.DateTimeConverter;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
 import static cn.reghao.autodop.common.result.ResultCode.*;
 
 /**
@@ -18,14 +24,24 @@ import static cn.reghao.autodop.common.result.ResultCode.*;
 @NoArgsConstructor
 public class WebBody {
     private static ObjectMapper objectMapper = new ObjectMapper();
+    static {
+        JavaTimeModule javaTimeModule = new JavaTimeModule();
+        javaTimeModule
+                .addSerializer(LocalDateTime.class,
+                        new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
+                .addDeserializer(LocalDateTime.class,
+                        new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        objectMapper.registerModule(javaTimeModule);
+    }
+
     private Integer code;
-    private String status;
+    private String msg;
     private String timestamp;
     private Object data;
 
-    private WebBody(Integer code, String status) {
+    private WebBody(Integer code, String msg) {
         this.code = code;
-        this.status = status;
+        this.msg = msg;
     }
 
     public static String success(Object data) {

+ 16 - 3
dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/ResourcePageController.java

@@ -1,12 +1,14 @@
 package cn.reghao.autodop.dmaster.view.controller;
 
+import cn.reghao.autodop.dmaster.auth.entity.GrantedAuthorityImpl;
+import cn.reghao.autodop.dmaster.auth.entity.Role;
+import cn.reghao.autodop.dmaster.auth.entity.User;
+import cn.reghao.autodop.dmaster.auth.repository.RoleRepository;
 import cn.reghao.autodop.dmaster.utils.WebBody;
 import cn.reghao.autodop.dmaster.auth.repository.UserRepository;
 import cn.reghao.autodop.dmaster.auth.entity.Menu;
 import cn.reghao.autodop.dmaster.auth.repository.MenuRepository;
-import cn.reghao.autodop.dmaster.common.db.PageList;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.data.domain.*;
 import org.springframework.http.MediaType;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -26,10 +28,14 @@ import java.util.stream.Collectors;
 @Controller
 public class ResourcePageController {
     private final UserRepository userRepository;
+    private final RoleRepository roleRepository;
     private final MenuRepository menuRepository;
 
-    public ResourcePageController(UserRepository userRepository, MenuRepository menuRepository) {
+    public ResourcePageController(UserRepository userRepository,
+                                  RoleRepository roleRepository,
+                                  MenuRepository menuRepository) {
         this.userRepository = userRepository;
+        this.roleRepository = roleRepository;
         this.menuRepository = menuRepository;
     }
 
@@ -82,4 +88,11 @@ public class ResourcePageController {
         //map.put("1", "用户管理");
         return WebBody.success(map);
     }
+
+    @GetMapping("/roleList/{id}")
+    public String roleListWithResource(@PathVariable("id") Role role, Model model) {
+        List<Role> list = roleRepository.findAll();
+        model.addAttribute("list", list);
+        return "/system/menu/roleList";
+    }
 }

+ 22 - 5
dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/RoleController.java

@@ -1,12 +1,16 @@
 package cn.reghao.autodop.dmaster.view.controller;
 
+import cn.reghao.autodop.dmaster.auth.repository.MenuRepository;
+import cn.reghao.autodop.dmaster.auth.repository.RoleRepository;
 import cn.reghao.autodop.dmaster.utils.WebBody;
 import cn.reghao.autodop.dmaster.auth.entity.Role;
 import cn.reghao.autodop.dmaster.auth.service.RoleService;
 import cn.reghao.autodop.dmaster.auth.entity.Menu;
+import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 
 
@@ -18,19 +22,32 @@ import java.util.List;
 @RestController
 public class RoleController {
     private RoleService roleService;
+    private MenuRepository menuRepository;
+    private RoleRepository roleRepository;
 
-    public RoleController(RoleService roleService) {
+    public RoleController(RoleService roleService, MenuRepository menuRepository, RoleRepository roleRepository) {
         this.roleService = roleService;
+        this.menuRepository = menuRepository;
+        this.roleRepository = roleRepository;
     }
 
-    @GetMapping("/authList")
+    @GetMapping(value = "/authList", produces = MediaType.APPLICATION_JSON_VALUE)
     public String authList(@RequestParam(value = "ids") Role role) {
-        List<Menu> list = new ArrayList<>();
+        List<Menu> list = menuRepository.findAll();
+        list.forEach(menu -> {
+            if (menu.getRoles().contains(role)) {
+                menu.setRemark("auth:true");
+            }
+        });
+
         return WebBody.success(list);
     }
 
-    @PostMapping("/auth")
-    public String auth() {
+    @PostMapping(value = "/auth", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String auth(@RequestParam(value = "id", required = true) Role role,
+                       @RequestParam(value = "authId", required = false) HashSet<Menu> menus) {
+        role.setMenus(menus);
+        roleRepository.save(role);
         return WebBody.success("ok");
     }
 

+ 12 - 6
dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/RolePageController.java

@@ -1,7 +1,9 @@
 package cn.reghao.autodop.dmaster.view.controller;
 
+import cn.reghao.autodop.dmaster.auth.entity.GrantedAuthorityImpl;
 import cn.reghao.autodop.dmaster.auth.entity.Role;
 import cn.reghao.autodop.dmaster.auth.entity.User;
+import cn.reghao.autodop.dmaster.auth.repository.UserRepository;
 import cn.reghao.autodop.dmaster.auth.service.RoleService;
 import cn.reghao.autodop.dmaster.common.db.PageList;
 import org.springframework.stereotype.Controller;
@@ -11,9 +13,8 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
-import java.util.ArrayList;
 import java.util.List;
-
+import java.util.stream.Collectors;
 
 /**
  * @author reghao
@@ -23,13 +24,15 @@ import java.util.List;
 @Controller
 public class RolePageController {
     private RoleService roleService;
+    private UserRepository userRepository;
 
-    public RolePageController(RoleService roleService) {
+    public RolePageController(RoleService roleService, UserRepository userRepository) {
         this.roleService = roleService;
+        this.userRepository = userRepository;
     }
 
     @GetMapping
-    public String rolePage(Model model) {
+    public String rolePage(Model model, Role role) {
         int page = 1;
         int size = 10;
         PageList<Role> pageList = roleService.findByPage(page, size);
@@ -65,8 +68,11 @@ public class RolePageController {
     }
 
     @GetMapping("/userList/{id}")
-    public String userListWithRole(@PathVariable("id") int roleId, Model model) {
-        List<User> list = new ArrayList<>();
+    public String userListWithRole(@PathVariable("id") Role role, Model model) {
+        List<User> list = userRepository.findAll().stream()
+                .filter(user -> user.getAuthorities().contains(new GrantedAuthorityImpl(role.getTitle())))
+                .collect(Collectors.toList());
+
         model.addAttribute("list", list);
         return "/system/role/userList";
     }

+ 8 - 11
dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/UserController.java

@@ -1,14 +1,13 @@
 package cn.reghao.autodop.dmaster.view.controller;
 
+import cn.reghao.autodop.dmaster.auth.entity.Role;
 import cn.reghao.autodop.dmaster.utils.WebBody;
 import cn.reghao.autodop.dmaster.auth.entity.User;
 import cn.reghao.autodop.dmaster.auth.service.UserService;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * @author reghao
@@ -17,7 +16,7 @@ import java.util.stream.Collectors;
 @RequestMapping("/system/user")
 @RestController
 public class UserController {
-    private final cn.reghao.autodop.dmaster.auth.service.UserService userService;
+    private final UserService userService;
 
     public UserController(UserService userService) {
         this.userService = userService;
@@ -26,7 +25,8 @@ public class UserController {
     @PostMapping("/save")
     @ResponseBody
     public String addOrUpdateUser(User user) {
-        return WebBody.success("");
+        userService.addOrUpdate(user);
+        return WebBody.success("ok");
     }
 
     @PostMapping("/pwd")
@@ -40,12 +40,9 @@ public class UserController {
 
     @PostMapping("/role")
     @ResponseBody
-    public String assignRole(@RequestParam(value = "id") int userId,
-                             @RequestParam(value = "roleId", required = false) String roleIds) {
-
-        Set<Integer> set = Arrays.stream(roleIds.split(","))
-                .map(Integer::parseInt)
-                .collect(Collectors.toSet());
+    public String assignRole(@RequestParam(value = "id") User user,
+                             @RequestParam(value = "roleId", required = false) HashSet<Role> roles) {
+        userService.modifyUserRoles(user, roles);
         return WebBody.success("ok");
     }
 }

+ 4 - 4
dmaster/src/main/java/cn/reghao/autodop/dmaster/view/controller/UserPageController.java

@@ -44,15 +44,15 @@ public class UserPageController {
 
     @GetMapping("/edit/{id}")
     public String editUserPage(@PathVariable("id") int id, Model model) {
-        /*User userInfo = userService.findById(id);
-        model.addAttribute("user", userInfo);*/
+        User userInfo = userService.findById(id);
+        model.addAttribute("user", userInfo);
         return "/system/user/add";
     }
 
     @GetMapping("/detail/{id}")
     public String userDetailPage(@PathVariable("id") int id, Model model) {
-        /*User userInfo = userService.findById(id);
-        model.addAttribute("user", userInfo);*/
+        User userInfo = userService.findById(id);
+        model.addAttribute("user", userInfo);
         return "/system/user/detail";
     }
 

+ 0 - 2
dmaster/src/main/resources/application.yml

@@ -39,8 +39,6 @@ spring:
           auto: update
         dialect: org.hibernate.dialect.MySQL57Dialect
   mvc:
-    favicon:
-      enabled: true
     dispatch-options-request: true
   thymeleaf:
     prefix: classpath:/templates

BIN
dmaster/src/main/resources/static/imgs/favicon.ico


BIN
dmaster/src/main/resources/static/imgs/mo-favicon.ico


+ 1 - 1
dmaster/src/main/resources/templates/common/template.html

@@ -16,7 +16,7 @@
     <meta name="description" content="DevOps 系统" />
     <meta name="keywords" content="DevOps, SpringBoot, Thymeleaf" />
 
-    <link rel="shortcut icon" th:href="@{/mo-favicon.ico}" type="image/x-icon">
+    <link rel="shortcut icon" th:href="@{/imgs/favicon.ico}" type="image/x-icon">
     <link rel="stylesheet" th:href="@{/css/plugins/font-awesome-4.7.0/css/font-awesome.min.css}"  media="all">
     <link rel="stylesheet" th:href="@{/lib/layui-v2.3.0/css/layui.css}"  media="all">
     <link rel="stylesheet" th:href="@{/css/main.css}"  media="all">

+ 1 - 1
dmaster/src/main/resources/templates/login.html

@@ -26,7 +26,7 @@
         </div>
         <div class="layui-form-item">
             <input type="checkbox" name="rememberMe" title="记住我" lay-skin="primary">
-            <a class="layui-layout-right forget-password" href="javascript:alert('请联系 reghaodev@gmail.com')">忘记密码?</a>
+            <a class="layui-layout-right forget-password" href="javascript:alert('请联系管理员')">没有帐号/忘记密码?</a>
         </div>
         <button type="submit" class="layui-btn layui-btn-fluid ajax-login">
             <i class="fa fa-sign-in fa-lg fa-fw"></i> 登录</button>

+ 6 - 2
dmaster/src/main/resources/templates/system/menu/index.html

@@ -90,7 +90,7 @@
                                     <th>URL 地址</th>
                                     <th>资源类型</th>
                                     <th>状态</th>
-                                    <th>角色列表</th>
+                                    <th>查看</th>
                                     <th>操作</th>
                                 </tr>
                             </thead>
@@ -106,7 +106,11 @@
                                     <td>{{url}}</td>
                                     <td>{{type}}</td>
                                     <td>正常</td>
-                                    <td>{{perms}}</td>
+                                    <td>
+                                        <a class="open-popup" data-title="角色列表"
+                                           th:attr="data-url=@{'/system/menu/roleList/{{id}}'}" data-size="800,600"
+                                           href="#">已授权角色</a>
+                                    </td>
                                     <td>
                                         <a class="open-popup popup-edit" data-title="编辑资源"
                                            th:attr="data-url=@{'/system/menu/edit/{{id}}'}" href="#">编辑

+ 38 - 0
dmaster/src/main/resources/templates/system/menu/roleList.html

@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+<head th:replace="/common/template :: header(~{::title},~{::link},~{::style})">
+    <style>
+        a{
+            color: #009688;
+        }
+        a:hover{
+            color: #004a43;
+            text-decoration: underline;
+        }
+    </style>
+</head>
+<body>
+    <div class="timo-detail-page">
+        <table class="layui-table">
+            <thead>
+            <tr>
+                <th>角色</th>
+                <th>角色名</th>
+                <th>操作</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr th:each="item:${list}">
+                <td>[[${item.title}]]</td>
+                <td>[[${item.name}]]</td>
+                <td><a th:href="@{/system/user/index(id=${item.id})}">查看</a></td>
+            </tr>
+            <tr th:if="${list.isEmpty()}">
+                <td style="text-align: center" colspan="3">未有分配该资源的角色</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+<script th:replace="/common/template :: script"></script>
+</body>
+</html>

+ 4 - 0
dmaster/src/main/resources/templates/system/role/auth.html

@@ -43,7 +43,10 @@
                 }
             }
         };
+
+        // 初始化 ztree
         $.get($("#authTree").data("url"), function(result){
+            console.log(result)
             var keyPid = [];
             result.data.forEach(function(item){
                 keyPid[item.pid] = true;
@@ -77,6 +80,7 @@
             $.fn.zTree.init($("#authTree"), setting, zNodes);
         });
 
+        // 提交请求
         $("#submit").click(function () {
             var zTreeObj = $.fn.zTree.getZTreeObj("authTree");
             var authList = zTreeObj.getCheckedNodes(true);

+ 4 - 5
dmaster/src/main/resources/templates/system/role/index.html

@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <html xmlns:th="http://www.thymeleaf.org"
-      xmlns:mo="https://gitee.com/aun/Timo"
-      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+      xmlns:mo="https://gitee.com/aun/Timo">
 <head th:replace="/common/template :: header(~{::title},~{::link},~{::style})">
 </head>
 <body class="timo-layout-page">
@@ -14,9 +13,9 @@
         <div class="layui-row timo-card-screen">
             <div class="pull-left layui-form-pane timo-search-box">
                 <div class="layui-inline">
-                    <label class="layui-form-label">名称</label>
+                    <label class="layui-form-label">角色</label>
                     <div class="layui-input-block">
-                        <input type="text" name="title" th:value="${param.name}" placeholder="请输入角色"
+                        <input type="text" name="title" th:value="${param.name}" placeholder="请输入角色"
                                autocomplete="off" class="layui-input">
                     </div>
                 </div>
@@ -64,7 +63,7 @@
                     <td>
                         <a class="open-popup" data-title="用户列表"
                            th:attr="data-url=@{'/system/role/userList/'+${item.id}}" data-size="800,600"
-                           href="#">用户列表</a>
+                           href="#">可访问的资源</a>
                     </td>
                     <td>
                         <a class="open-popup" data-title="编辑角色" th:attr="data-url=@{'/system/role/edit/'+${item.id}}"

+ 2 - 0
dmaster/src/main/resources/templates/system/user/index.html

@@ -78,6 +78,7 @@
                     <th class="sortable" data-field="email">邮箱</th>
                     <th class="sortable" data-field="createDate">创建时间</th>
                     <th>状态</th>
+                    <th>已授予的角色</th>
                     <th>操作</th>
                 </tr>
                 </thead>
@@ -92,6 +93,7 @@
                     <td th:text="${item.email}">邮箱</td>
                     <td th:text="${item.createTime}">创建时间</td>
                     <td th:text="正常">状态</td>
+                    <td th:text="查看">已授予的角色</td>
                     <td>
                         <a class="open-popup" data-title="编辑用户" th:attr="data-url=@{'/system/user/edit/'+${item.id}}"
                            data-size="600,570" href="#">编辑</a>