Browse Source

完成用户列表的前后端对接

YunaiV 4 years ago
parent
commit
f5b7142ab6
18 changed files with 480 additions and 319 deletions
  1. 59 191
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
  2. 6 6
      ruoyi-ui/src/api/system/user.js
  3. 71 95
      ruoyi-ui/src/views/system/user/index.vue
  4. 14 0
      src/main/java/cn/iocoder/dashboard/common/pojo/PageResult.java
  5. 1 1
      src/main/java/cn/iocoder/dashboard/framework/security/core/LoginUser.java
  6. 1 2
      src/main/java/cn/iocoder/dashboard/framework/security/core/handler/AccessDeniedHandlerImpl.java
  7. 1 1
      src/main/java/cn/iocoder/dashboard/framework/security/core/util/SecurityUtils.java
  8. 56 10
      src/main/java/cn/iocoder/dashboard/modules/system/controller/user/SysUserController.java
  9. 34 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/user/vo/user/SysUserPageItemRespVO.java
  10. 43 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/user/vo/user/SysUserPageReqVO.java
  11. 24 0
      src/main/java/cn/iocoder/dashboard/modules/system/convert/user/SysUserConvert.java
  12. 16 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java
  13. 4 4
      src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java
  14. 23 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptService.java
  15. 84 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java
  16. 6 6
      src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java
  17. 11 1
      src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java
  18. 26 2
      src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java

+ 59 - 191
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java

@@ -2,6 +2,7 @@ package com.ruoyi.system.service.impl;
 
 import java.util.ArrayList;
 import java.util.List;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -27,86 +28,38 @@ import com.ruoyi.system.service.ISysUserService;
 
 /**
  * 用户 业务层处理
- * 
+ *
  * @author ruoyi
  */
 @Service
-public class SysUserServiceImpl implements ISysUserService
-{
-    private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);
-
-    @Autowired
-    private SysUserMapper userMapper;
-
-    @Autowired
-    private SysRoleMapper roleMapper;
-
-    @Autowired
-    private SysPostMapper postMapper;
-
-    @Autowired
-    private SysUserRoleMapper userRoleMapper;
-
-    @Autowired
-    private SysUserPostMapper userPostMapper;
-
-    @Autowired
-    private ISysConfigService configService;
+public class SysUserServiceImpl implements ISysUserService {
 
     /**
      * 根据条件分页查询用户列表
-     * 
+     *
      * @param user 用户信息
      * @return 用户信息集合信息
      */
     @Override
     @DataScope(deptAlias = "d", userAlias = "u")
-    public List<SysUser> selectUserList(SysUser user)
-    {
+    public List<SysUser> selectUserList(SysUser user) {
         return userMapper.selectUserList(user);
     }
 
-    /**
-     * 通过用户名查询用户
-     * 
-     * @param userName 用户名
-     * @return 用户对象信息
-     */
-    @Override
-    public SysUser selectUserByUserName(String userName)
-    {
-        return userMapper.selectUserByUserName(userName);
-    }
-
-    /**
-     * 通过用户ID查询用户
-     * 
-     * @param userId 用户ID
-     * @return 用户对象信息
-     */
-    @Override
-    public SysUser selectUserById(Long userId)
-    {
-        return userMapper.selectUserById(userId);
-    }
-
     /**
      * 查询用户所属角色组
-     * 
+     *
      * @param userName 用户名
      * @return 结果
      */
     @Override
-    public String selectUserRoleGroup(String userName)
-    {
+    public String selectUserRoleGroup(String userName) {
         List<SysRole> list = roleMapper.selectRolesByUserName(userName);
         StringBuffer idsStr = new StringBuffer();
-        for (SysRole role : list)
-        {
+        for (SysRole role : list) {
             idsStr.append(role.getRoleName()).append(",");
         }
-        if (StringUtils.isNotEmpty(idsStr.toString()))
-        {
+        if (StringUtils.isNotEmpty(idsStr.toString())) {
             return idsStr.substring(0, idsStr.length() - 1);
         }
         return idsStr.toString();
@@ -114,61 +67,23 @@ public class SysUserServiceImpl implements ISysUserService
 
     /**
      * 查询用户所属岗位组
-     * 
+     *
      * @param userName 用户名
      * @return 结果
      */
     @Override
-    public String selectUserPostGroup(String userName)
-    {
+    public String selectUserPostGroup(String userName) {
         List<SysPost> list = postMapper.selectPostsByUserName(userName);
         StringBuffer idsStr = new StringBuffer();
-        for (SysPost post : list)
-        {
+        for (SysPost post : list) {
             idsStr.append(post.getPostName()).append(",");
         }
-        if (StringUtils.isNotEmpty(idsStr.toString()))
-        {
+        if (StringUtils.isNotEmpty(idsStr.toString())) {
             return idsStr.substring(0, idsStr.length() - 1);
         }
         return idsStr.toString();
     }
 
-    /**
-     * 校验用户名称是否唯一
-     * 
-     * @param userName 用户名称
-     * @return 结果
-     */
-    @Override
-    public String checkUserNameUnique(String userName)
-    {
-        int count = userMapper.checkUserNameUnique(userName);
-        if (count > 0)
-        {
-            return UserConstants.NOT_UNIQUE;
-        }
-        return UserConstants.UNIQUE;
-    }
-
-    /**
-     * 校验用户名称是否唯一
-     *
-     * @param user 用户信息
-     * @return
-     */
-    @Override
-    public String checkPhoneUnique(SysUser user)
-    {
-        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
-        SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
-        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
-        {
-            return UserConstants.NOT_UNIQUE;
-        }
-        return UserConstants.UNIQUE;
-    }
-
     /**
      * 校验email是否唯一
      *
@@ -176,12 +91,10 @@ public class SysUserServiceImpl implements ISysUserService
      * @return
      */
     @Override
-    public String checkEmailUnique(SysUser user)
-    {
+    public String checkEmailUnique(SysUser user) {
         Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
         SysUser info = userMapper.checkEmailUnique(user.getEmail());
-        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
-        {
+        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -189,28 +102,25 @@ public class SysUserServiceImpl implements ISysUserService
 
     /**
      * 校验用户是否允许操作
-     * 
+     *
      * @param user 用户信息
      */
     @Override
-    public void checkUserAllowed(SysUser user)
-    {
-        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
-        {
+    public void checkUserAllowed(SysUser user) {
+        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) {
             throw new CustomException("不允许操作超级管理员用户");
         }
     }
 
     /**
      * 新增保存用户信息
-     * 
+     *
      * @param user 用户信息
      * @return 结果
      */
     @Override
     @Transactional
-    public int insertUser(SysUser user)
-    {
+    public int insertUser(SysUser user) {
         // 新增用户信息
         int rows = userMapper.insertUser(user);
         // 新增用户岗位关联
@@ -222,14 +132,13 @@ public class SysUserServiceImpl implements ISysUserService
 
     /**
      * 修改保存用户信息
-     * 
+     *
      * @param user 用户信息
      * @return 结果
      */
     @Override
     @Transactional
-    public int updateUser(SysUser user)
-    {
+    public int updateUser(SysUser user) {
         Long userId = user.getUserId();
         // 删除用户与角色关联
         userRoleMapper.deleteUserRoleByUserId(userId);
@@ -242,89 +151,69 @@ public class SysUserServiceImpl implements ISysUserService
         return userMapper.updateUser(user);
     }
 
-    /**
-     * 修改用户状态
-     * 
-     * @param user 用户信息
-     * @return 结果
-     */
-    @Override
-    public int updateUserStatus(SysUser user)
-    {
-        return userMapper.updateUser(user);
-    }
-
     /**
      * 修改用户基本信息
-     * 
+     *
      * @param user 用户信息
      * @return 结果
      */
     @Override
-    public int updateUserProfile(SysUser user)
-    {
+    public int updateUserProfile(SysUser user) {
         return userMapper.updateUser(user);
     }
 
     /**
      * 修改用户头像
-     * 
+     *
      * @param userName 用户名
-     * @param avatar 头像地址
+     * @param avatar   头像地址
      * @return 结果
      */
     @Override
-    public boolean updateUserAvatar(String userName, String avatar)
-    {
+    public boolean updateUserAvatar(String userName, String avatar) {
         return userMapper.updateUserAvatar(userName, avatar) > 0;
     }
 
     /**
      * 重置用户密码
-     * 
+     *
      * @param user 用户信息
      * @return 结果
      */
     @Override
-    public int resetPwd(SysUser user)
-    {
+    public int resetPwd(SysUser user) {
         return userMapper.updateUser(user);
     }
 
     /**
      * 重置用户密码
-     * 
+     *
      * @param userName 用户名
      * @param password 密码
      * @return 结果
      */
     @Override
-    public int resetUserPwd(String userName, String password)
-    {
+    public int resetUserPwd(String userName, String password) {
         return userMapper.resetUserPwd(userName, password);
     }
 
     /**
      * 新增用户角色信息
-     * 
+     *
      * @param user 用户对象
      */
-    public void insertUserRole(SysUser user)
-    {
+    public void insertUserRole(SysUser user) {
         Long[] roles = user.getRoleIds();
-        if (StringUtils.isNotNull(roles))
-        {
+        if (StringUtils.isNotNull(roles)) {
             // 新增用户与角色管理
             List<SysUserRole> list = new ArrayList<SysUserRole>();
-            for (Long roleId : roles)
-            {
+            for (Long roleId : roles) {
                 SysUserRole ur = new SysUserRole();
                 ur.setUserId(user.getUserId());
                 ur.setRoleId(roleId);
                 list.add(ur);
             }
-            if (list.size() > 0)
-            {
+            if (list.size() > 0) {
                 userRoleMapper.batchUserRole(list);
             }
         }
@@ -332,25 +221,21 @@ public class SysUserServiceImpl implements ISysUserService
 
     /**
      * 新增用户岗位信息
-     * 
+     *
      * @param user 用户对象
      */
-    public void insertUserPost(SysUser user)
-    {
+    public void insertUserPost(SysUser user) {
         Long[] posts = user.getPostIds();
-        if (StringUtils.isNotNull(posts))
-        {
+        if (StringUtils.isNotNull(posts)) {
             // 新增用户与岗位管理
             List<SysUserPost> list = new ArrayList<SysUserPost>();
-            for (Long postId : posts)
-            {
+            for (Long postId : posts) {
                 SysUserPost up = new SysUserPost();
                 up.setUserId(user.getUserId());
                 up.setPostId(postId);
                 list.add(up);
             }
-            if (list.size() > 0)
-            {
+            if (list.size() > 0) {
                 userPostMapper.batchUserPost(list);
             }
         }
@@ -358,14 +243,13 @@ public class SysUserServiceImpl implements ISysUserService
 
     /**
      * 通过用户ID删除用户
-     * 
+     *
      * @param userId 用户ID
      * @return 结果
      */
     @Override
     @Transactional
-    public int deleteUserById(Long userId)
-    {
+    public int deleteUserById(Long userId) {
         // 删除用户与角色关联
         userRoleMapper.deleteUserRoleByUserId(userId);
         // 删除用户与岗位表
@@ -375,16 +259,14 @@ public class SysUserServiceImpl implements ISysUserService
 
     /**
      * 批量删除用户信息
-     * 
+     *
      * @param userIds 需要删除的用户ID
      * @return 结果
      */
     @Override
     @Transactional
-    public int deleteUserByIds(Long[] userIds)
-    {
-        for (Long userId : userIds)
-        {
+    public int deleteUserByIds(Long[] userIds) {
+        for (Long userId : userIds) {
             checkUserAllowed(new SysUser(userId));
         }
         // 删除用户与角色关联
@@ -396,17 +278,15 @@ public class SysUserServiceImpl implements ISysUserService
 
     /**
      * 导入用户数据
-     * 
-     * @param userList 用户数据列表
+     *
+     * @param userList        用户数据列表
      * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
-     * @param operName 操作用户
+     * @param operName        操作用户
      * @return 结果
      */
     @Override
-    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName)
-    {
-        if (StringUtils.isNull(userList) || userList.size() == 0)
-        {
+    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
+        if (StringUtils.isNull(userList) || userList.size() == 0) {
             throw new CustomException("导入用户数据不能为空!");
         }
         int successNum = 0;
@@ -414,48 +294,36 @@ public class SysUserServiceImpl implements ISysUserService
         StringBuilder successMsg = new StringBuilder();
         StringBuilder failureMsg = new StringBuilder();
         String password = configService.selectConfigByKey("sys.user.initPassword");
-        for (SysUser user : userList)
-        {
-            try
-            {
+        for (SysUser user : userList) {
+            try {
                 // 验证是否存在这个用户
                 SysUser u = userMapper.selectUserByUserName(user.getUserName());
-                if (StringUtils.isNull(u))
-                {
+                if (StringUtils.isNull(u)) {
                     user.setPassword(SecurityUtils.encryptPassword(password));
                     user.setCreateBy(operName);
                     this.insertUser(user);
                     successNum++;
                     successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
-                }
-                else if (isUpdateSupport)
-                {
+                } else if (isUpdateSupport) {
                     user.setUpdateBy(operName);
                     this.updateUser(user);
                     successNum++;
                     successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
-                }
-                else
-                {
+                } else {
                     failureNum++;
                     failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
                 }
-            }
-            catch (Exception e)
-            {
+            } catch (Exception e) {
                 failureNum++;
                 String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败:";
                 failureMsg.append(msg + e.getMessage());
                 log.error(msg, e);
             }
         }
-        if (failureNum > 0)
-        {
+        if (failureNum > 0) {
             failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
             throw new CustomException(failureMsg.toString());
-        }
-        else
-        {
+        } else {
             successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
         }
         return successMsg.toString();

+ 6 - 6
ruoyi-ui/src/api/system/user.js

@@ -4,7 +4,7 @@ import { praseStrEmpty } from "@/utils/ruoyi";
 // 查询用户列表
 export function listUser(query) {
   return request({
-    url: '/system/user/list',
+    url: '/system/user/page',
     method: 'get',
     params: query
   })
@@ -13,7 +13,7 @@ export function listUser(query) {
 // 查询用户详细
 export function getUser(userId) {
   return request({
-    url: '/system/user/' + praseStrEmpty(userId),
+    url: '/system/user/get?id=' + praseStrEmpty(userId),
     method: 'get'
   })
 }
@@ -21,7 +21,7 @@ export function getUser(userId) {
 // 新增用户
 export function addUser(data) {
   return request({
-    url: '/system/user',
+    url: '/system/user/create',
     method: 'post',
     data: data
   })
@@ -30,7 +30,7 @@ export function addUser(data) {
 // 修改用户
 export function updateUser(data) {
   return request({
-    url: '/system/user',
+    url: '/system/user/update',
     method: 'put',
     data: data
   })
@@ -39,7 +39,7 @@ export function updateUser(data) {
 // 删除用户
 export function delUser(userId) {
   return request({
-    url: '/system/user/' + userId,
+    url: '/system/user/delete?id=' + userId,
     method: 'delete'
   })
 }
@@ -73,7 +73,7 @@ export function changeUserStatus(userId, status) {
     status
   }
   return request({
-    url: '/system/user/changeStatus',
+    url: '/system/user/updateStatus',
     method: 'put',
     data: data
   })

+ 71 - 95
ruoyi-ui/src/views/system/user/index.vue

@@ -28,9 +28,9 @@
       <!--用户数据-->
       <el-col :span="20" :xs="24">
         <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-          <el-form-item label="用户名称" prop="userName">
+          <el-form-item label="用户名称" prop="username">
             <el-input
-              v-model="queryParams.userName"
+              v-model="queryParams.username"
               placeholder="请输入用户名称"
               clearable
               size="small"
@@ -38,9 +38,9 @@
               @keyup.enter.native="handleQuery"
             />
           </el-form-item>
-          <el-form-item label="手机号码" prop="phonenumber">
+          <el-form-item label="手机号码" prop="mobile">
             <el-input
-              v-model="queryParams.phonenumber"
+              v-model="queryParams.mobile"
               placeholder="请输入手机号码"
               clearable
               size="small"
@@ -57,10 +57,10 @@
               style="width: 240px"
             >
               <el-option
-                v-for="dict in statusOptions"
-                :key="dict.dictValue"
-                :label="dict.dictLabel"
-                :value="dict.dictValue"
+                  v-for="dict in statusDictDatas"
+                  :key="parseInt(dict.value)"
+                  :label="dict.label"
+                  :value="parseInt(dict.value)"
               />
             </el-select>
           </el-form-item>
@@ -92,26 +92,6 @@
               v-hasPermi="['system:user:add']"
             >新增</el-button>
           </el-col>
-          <el-col :span="1.5">
-            <el-button
-              type="success"
-              icon="el-icon-edit"
-              size="mini"
-              :disabled="single"
-              @click="handleUpdate"
-              v-hasPermi="['system:user:edit']"
-            >修改</el-button>
-          </el-col>
-          <el-col :span="1.5">
-            <el-button
-              type="danger"
-              icon="el-icon-delete"
-              size="mini"
-              :disabled="multiple"
-              @click="handleDelete"
-              v-hasPermi="['system:user:remove']"
-            >删除</el-button>
-          </el-col>
           <el-col :span="1.5">
             <el-button
               type="info"
@@ -133,20 +113,19 @@
           <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
         </el-row>
 
-        <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
-          <el-table-column type="selection" width="50" align="center" />
-          <el-table-column label="用户编号" align="center" prop="userId" />
-          <el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
-          <el-table-column label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
-          <el-table-column label="部门" align="center" prop="dept.deptName" :show-overflow-tooltip="true" />
-          <el-table-column label="手机号码" align="center" prop="phonenumber" width="120" />
+        <el-table v-loading="loading" :data="userList">
+          <el-table-column label="用户编号" align="center" prop="id" />
+          <el-table-column label="用户名称" align="center" prop="username" :show-overflow-tooltip="true" />
+          <el-table-column label="用户昵称" align="center" prop="nickname" :show-overflow-tooltip="true" />
+          <el-table-column label="部门" align="center" prop="dept.name" :show-overflow-tooltip="true" />
+          <el-table-column label="手机号码" align="center" prop="mobile" width="120" />
           <el-table-column label="状态" align="center">
             <template slot-scope="scope">
               <el-switch
-                v-model="scope.row.status"
-                active-value="0"
-                inactive-value="1"
-                @change="handleStatusChange(scope.row)"
+                  v-model="scope.row.status"
+                  :active-value="0"
+                  :inactive-value="1"
+                  @change="handleStatusChange(scope.row)"
               ></el-switch>
             </template>
           </el-table-column>
@@ -170,7 +149,7 @@
                 v-hasPermi="['system:user:edit']"
               >修改</el-button>
               <el-button
-                v-if="scope.row.userId !== 1"
+                v-if="scope.row.id !== 1"
                 size="mini"
                 type="text"
                 icon="el-icon-delete"
@@ -191,7 +170,7 @@
         <pagination
           v-show="total>0"
           :total="total"
-          :page.sync="queryParams.pageNum"
+          :page.sync="queryParams.pageNo"
           :limit.sync="queryParams.pageSize"
           @pagination="getList"
         />
@@ -203,8 +182,8 @@
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
         <el-row>
           <el-col :span="12">
-            <el-form-item label="用户昵称" prop="nickName">
-              <el-input v-model="form.nickName" placeholder="请输入用户昵称" />
+            <el-form-item label="用户昵称" prop="nickname">
+              <el-input v-model="form.nickname" placeholder="请输入用户昵称" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -215,8 +194,8 @@
         </el-row>
         <el-row>
           <el-col :span="12">
-            <el-form-item label="手机号码" prop="phonenumber">
-              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+            <el-form-item label="手机号码" prop="mobile">
+              <el-input v-model="form.mobile" placeholder="请输入手机号码" maxlength="11" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -227,12 +206,12 @@
         </el-row>
         <el-row>
           <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
-              <el-input v-model="form.userName" placeholder="请输入用户名称" />
+            <el-form-item v-if="form.id === undefined" label="用户名称" prop="username">
+              <el-input v-model="form.username" placeholder="请输入用户名称" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
+            <el-form-item v-if="form.id === undefined" label="用户密码" prop="password">
               <el-input v-model="form.password" placeholder="请输入用户密码" type="password" />
             </el-form-item>
           </el-col>
@@ -344,6 +323,11 @@ import { treeselect } from "@/api/system/dept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
+import {listSimpleDepts} from "@/api/system/dept";
+
+import {SysCommonStatusEnum} from "@/utils/constants";
+import {DICT_TYPE, getDictDatas} from "@/utils/dict";
+
 export default {
   name: "User",
   components: { Treeselect },
@@ -351,12 +335,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
       // 显示搜索条件
       showSearch: true,
       // 总条数
@@ -387,7 +365,7 @@ export default {
       form: {},
       defaultProps: {
         children: "children",
-        label: "label"
+        label: "name"
       },
       // 用户导入参数
       upload: {
@@ -406,19 +384,19 @@ export default {
       },
       // 查询参数
       queryParams: {
-        pageNum: 1,
+        pageNo: 1,
         pageSize: 10,
-        userName: undefined,
-        phonenumber: undefined,
+        username: undefined,
+        mobile: undefined,
         status: undefined,
         deptId: undefined
       },
       // 表单校验
       rules: {
-        userName: [
+        username: [
           { required: true, message: "用户名称不能为空", trigger: "blur" }
         ],
-        nickName: [
+        nickname: [
           { required: true, message: "用户昵称不能为空", trigger: "blur" }
         ],
         password: [
@@ -431,14 +409,19 @@ export default {
             trigger: ["blur", "change"]
           }
         ],
-        phonenumber: [
+        mobile: [
           {
             pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
             message: "请输入正确的手机号码",
             trigger: "blur"
           }
         ]
-      }
+      },
+
+      // 枚举
+      SysCommonStatusEnum: SysCommonStatusEnum,
+      // 数据字典
+      statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
     };
   },
   watch: {
@@ -450,12 +433,6 @@ export default {
   created() {
     this.getList();
     this.getTreeselect();
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
-    this.getDicts("sys_user_sex").then(response => {
-      this.sexOptions = response.data;
-    });
     this.getConfigKey("sys.user.initPassword").then(response => {
       this.initPassword = response.msg;
     });
@@ -464,23 +441,28 @@ export default {
     /** 查询用户列表 */
     getList() {
       this.loading = true;
-      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
-          this.userList = response.rows;
-          this.total = response.total;
+      listUser(this.addDateRange(this.queryParams, [
+        this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
+        this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
+      ])).then(response => {
+          this.userList = response.data.list;
+          this.total = response.data.list;
           this.loading = false;
         }
       );
     },
     /** 查询部门下拉树结构 */
     getTreeselect() {
-      treeselect().then(response => {
-        this.deptOptions = response.data;
+      listSimpleDepts().then(response => {
+        // 处理 menuOptions 参数
+        this.deptOptions = [];
+        this.deptOptions.push(...this.handleTree(response.data, "id"));
       });
     },
     // 筛选节点
     filterNode(value, data) {
       if (!value) return true;
-      return data.label.indexOf(value) !== -1;
+      return data.name.indexOf(value) !== -1;
     },
     // 节点单击事件
     handleNodeClick(data) {
@@ -490,12 +472,12 @@ export default {
     // 用户状态修改
     handleStatusChange(row) {
       let text = row.status === "0" ? "启用" : "停用";
-      this.$confirm('确认要"' + text + '""' + row.userName + '"用户吗?', "警告", {
+      this.$confirm('确认要"' + text + '""' + row.username + '"用户吗?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return changeUserStatus(row.userId, row.status);
+          return changeUserStatus(row.id, row.status);
         }).then(() => {
           this.msgSuccess(text + "成功");
         }).catch(function() {
@@ -510,12 +492,12 @@ export default {
     // 表单重置
     reset() {
       this.form = {
-        userId: undefined,
+        id: undefined,
         deptId: undefined,
-        userName: undefined,
-        nickName: undefined,
+        username: undefined,
+        nickname: undefined,
         password: undefined,
-        phonenumber: undefined,
+        mobile: undefined,
         email: undefined,
         sex: undefined,
         status: "0",
@@ -536,12 +518,6 @@ export default {
       this.resetForm("queryForm");
       this.handleQuery();
     },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.userId);
-      this.single = selection.length != 1;
-      this.multiple = !selection.length;
-    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
@@ -558,8 +534,8 @@ export default {
     handleUpdate(row) {
       this.reset();
       this.getTreeselect();
-      const userId = row.userId || this.ids;
-      getUser(userId).then(response => {
+      const id = row.id;
+      getUser(id).then(response => {
         this.form = response.data;
         this.postOptions = response.posts;
         this.roleOptions = response.roles;
@@ -572,11 +548,11 @@ export default {
     },
     /** 重置密码按钮操作 */
     handleResetPwd(row) {
-      this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
+      this.$prompt('请输入"' + row.username + '"的新密码', "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消"
       }).then(({ value }) => {
-          resetUserPwd(row.userId, value).then(response => {
+          resetUserPwd(row.id, value).then(response => {
             this.msgSuccess("修改成功,新密码是:" + value);
           });
         }).catch(() => {});
@@ -585,7 +561,7 @@ export default {
     submitForm: function() {
       this.$refs["form"].validate(valid => {
         if (valid) {
-          if (this.form.userId != undefined) {
+          if (this.form.id != undefined) {
             updateUser(this.form).then(response => {
               this.msgSuccess("修改成功");
               this.open = false;
@@ -603,13 +579,13 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      const userIds = row.userId || this.ids;
-      this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', "警告", {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除用户编号为"' + ids + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delUser(userIds);
+          return delUser(ids);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
@@ -657,4 +633,4 @@ export default {
     }
   }
 };
-</script>
+</script>

+ 14 - 0
src/main/java/cn/iocoder/dashboard/common/pojo/PageResult.java

@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
 
 @ApiModel("分页结果")
@@ -17,4 +18,17 @@ public final class PageResult<T> implements Serializable {
     @ApiModelProperty(value = "总量", required = true)
     private Long total;
 
+    public PageResult() {
+    }
+
+    public PageResult(List<T> list, Long total) {
+        this.list = list;
+        this.total = total;
+    }
+
+    public PageResult(Long total) {
+        this.list = new ArrayList<>();
+        this.total = total;
+    }
+
 }

+ 1 - 1
src/main/java/cn/iocoder/dashboard/framework/security/core/LoginUser.java

@@ -21,7 +21,7 @@ public class LoginUser implements UserDetails {
     /**
      * 用户编号
      */
-    private Long userId;
+    private Long id;
     /**
      * 科室编号
      */

+ 1 - 2
src/main/java/cn/iocoder/dashboard/framework/security/core/handler/AccessDeniedHandlerImpl.java

@@ -6,7 +6,6 @@ import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils;
 import cn.iocoder.dashboard.util.servlet.ServletUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.access.AccessDeniedHandler;
 import org.springframework.security.web.access.ExceptionTranslationFilter;
 import org.springframework.stereotype.Component;
@@ -36,7 +35,7 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
             throws IOException, ServletException {
         // 打印 warn 的原因是,不定期合并 warn,看看有没恶意破坏
         log.warn("[commence][访问 URL({}) 时,用户({}) 权限不够]", request.getRequestURI(),
-                SecurityUtils.getLoginUser().getUserId(), e);
+                SecurityUtils.getLoginUser().getId(), e);
         // 返回 403
         ServletUtils.writeJSON(response, CommonResult.error(UNAUTHORIZED));
     }

+ 1 - 1
src/main/java/cn/iocoder/dashboard/framework/security/core/util/SecurityUtils.java

@@ -50,7 +50,7 @@ public class SecurityUtils {
      * @return 用户编号
      */
     public static Long getLoginUserId() {
-        return getLoginUser().getUserId();
+        return getLoginUser().getId();
     }
 
     public static Set<Long> getLoginUserRoleIds() {

+ 56 - 10
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/SysUserController.java

@@ -1,18 +1,64 @@
 package cn.iocoder.dashboard.modules.system.controller.user;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.dashboard.common.pojo.CommonResult;
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageItemRespVO;
+import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageReqVO;
+import cn.iocoder.dashboard.modules.system.convert.user.SysUserConvert;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
+import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService;
+import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
+import cn.iocoder.dashboard.util.collection.CollectionUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
+
+@Api(tags = "用户 API")
+@RestController
+@RequestMapping("/system/user")
 public class SysUserController {
 
-//    /**
-//     * 获取用户列表
-//     */
+    @Resource
+    private SysUserService userService;
+    @Resource
+    private SysDeptService deptService;
+
+    @ApiOperation("获得用户分页列表")
+    @GetMapping("/page")
 //    @PreAuthorize("@ss.hasPermi('system:user:list')")
-//    @GetMapping("/list")
-//    public TableDataInfo list(SysUser user)
-//    {
-//        startPage();
-//        List<SysUser> list = userService.selectUserList(user);
-//        return getDataTable(list);
-//    }
+    public CommonResult<PageResult<SysUserPageItemRespVO>> pageUsers(SysUserPageReqVO reqVO) {
+        // 获得用户分页列表
+        PageResult<SysUserDO> pageResult = userService.pageUsers(reqVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(new PageResult<>(pageResult.getTotal())); // 返回空
+        }
+
+        // 获得拼接需要的数据
+        Map<Long, SysDeptDO> deptMap;
+        Collection<Long> deptIds = CollectionUtils.convertList(pageResult.getList(), SysUserDO::getDeptId);
+        if (CollUtil.isNotEmpty(deptIds)) {
+            deptMap = CollectionUtils.convertMap(deptService.listDepts(deptIds), SysDeptDO::getId);
+        } else {
+            deptMap = Collections.emptyMap();
+        }
+        // 拼接结果返回
+        List<SysUserPageItemRespVO> userList = new ArrayList<>(pageResult.getList().size());
+        pageResult.getList().forEach(user -> {
+            SysUserPageItemRespVO respVO = SysUserConvert.INSTANCE.convert(user);
+            respVO.setDept(SysUserConvert.INSTANCE.convert(deptMap.get(user.getDeptId())));
+            userList.add(respVO);
+        });
+        return success(new PageResult<>(userList, pageResult.getTotal()));
+    }
 //
 //    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
 //    @PreAuthorize("@ss.hasPermi('system:user:export')")

+ 34 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/vo/user/SysUserPageItemRespVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.dashboard.modules.system.controller.user.vo.user;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+@ApiModel(value = "用户分页时的信息 Response VO", description = "相比用户基本信息来说,会多部门信息")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysUserPageItemRespVO extends SysUserRespVO {
+
+    /**
+     * 所在部门
+     */
+    private Dept dept;
+
+    @ApiModel("部门")
+    @Data
+    public static class Dept {
+
+        @ApiModelProperty(value = "部门编号", required = true, example = "1")
+        private Integer id;
+
+        @ApiModelProperty(value = "部门名称", required = true, example = "研发部")
+        private String name;
+
+    }
+
+}

+ 43 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/vo/user/SysUserPageReqVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.dashboard.modules.system.controller.user.vo.user;
+
+import cn.iocoder.dashboard.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("用户分页 Request VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysUserPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配")
+    private String username;
+
+    @ApiModelProperty(value = "手机号码", example = "yudao", notes = "模糊匹配")
+    private String mobile;
+
+    @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
+    private Integer status;
+
+    @ApiModelProperty(value = "开始时间", example = "2020-10-24")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date beginTime;
+
+    @ApiModelProperty(value = "结束时间", example = "2020-10-24")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date endTime;
+
+    @ApiModelProperty(value = "部门编号", example = "1024", notes = "同时筛选子部门")
+    private Long deptId;
+
+}

+ 24 - 0
src/main/java/cn/iocoder/dashboard/modules/system/convert/user/SysUserConvert.java

@@ -0,0 +1,24 @@
+package cn.iocoder.dashboard.modules.system.convert.user;
+
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageItemRespVO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.factory.Mappers;
+
+@Mapper
+public interface SysUserConvert {
+
+    SysUserConvert INSTANCE = Mappers.getMapper(SysUserConvert.class);
+
+    SysUserPageItemRespVO convert(SysUserDO bean);
+
+    SysUserPageItemRespVO.Dept convert(SysDeptDO bean);
+
+    @Mapping(source = "records", target = "list")
+    PageResult<SysUserDO> convertPage(IPage<SysUserDO> page);
+
+}

+ 16 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java

@@ -1,10 +1,16 @@
 package cn.iocoder.dashboard.modules.system.dal.mysql.dao.user;
 
+import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
+import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils;
+import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageReqVO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 @Mapper
 public interface SysUserMapper extends BaseMapper<SysUserDO> {
 
@@ -12,4 +18,14 @@ public interface SysUserMapper extends BaseMapper<SysUserDO> {
         return selectOne(new QueryWrapper<SysUserDO>().eq("username", username));
     }
 
+    default IPage<SysUserDO> selectList(SysUserPageReqVO reqVO, List<Long> deptIds) {
+        return selectPage(MyBatisUtils.buildPage(reqVO),
+                new QueryWrapperX<SysUserDO>().likeIfPresent("username", reqVO.getUsername())
+                        .likeIfPresent("mobile", reqVO.getMobile())
+                        .eqIfPresent("status", reqVO.getStatus())
+                        .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime())
+                        .inIfPresent("dept_id", deptIds));
+    }
+
 }
+

+ 4 - 4
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java

@@ -80,7 +80,7 @@ public class SysAuthServiceImpl implements SysAuthService {
         // 创建 LoginUser 对象
         LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
         loginUser.setUpdateTime(new Date());
-        loginUser.setRoleIds(this.getUserRoleIds(loginUser.getUserId()));
+        loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
         return loginUser;
     }
 
@@ -94,7 +94,7 @@ public class SysAuthServiceImpl implements SysAuthService {
         // 缓存登陆用户到 Redis 中
         String sessionId = IdUtil.fastSimpleUUID();
         loginUser.setUpdateTime(new Date());
-        loginUser.setRoleIds(this.getUserRoleIds(loginUser.getUserId()));
+        loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
         loginUserRedisDAO.set(sessionId, loginUser);
 
         // 创建 Token
@@ -197,7 +197,7 @@ public class SysAuthServiceImpl implements SysAuthService {
         }
 
         // 重新加载 SysUserDO 信息
-        SysUserDO user = userService.getUser(loginUser.getUserId());
+        SysUserDO user = userService.getUser(loginUser.getId());
         if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) {
             throw exception(TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登陆界面
         }
@@ -205,7 +205,7 @@ public class SysAuthServiceImpl implements SysAuthService {
         // 刷新 LoginUser 缓存
         loginUser.setDeptId(user.getDeptId());
         loginUser.setUpdateTime(new Date());
-        loginUser.setRoleIds(this.getUserRoleIds(loginUser.getUserId()));
+        loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
         loginUserRedisDAO.set(sessionId, loginUser);
     }
 

+ 23 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptService.java

@@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.service.dept;
 import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -12,6 +13,11 @@ import java.util.List;
  */
 public interface SysDeptService {
 
+    /**
+     * 初始化
+     */
+    void init();
+
     /**
      * 获得所有部门列表
      *
@@ -19,6 +25,14 @@ public interface SysDeptService {
      */
     List<SysDeptDO> listDepts();
 
+    /**
+     * 获得指定编号的部门列表
+     *
+     * @param ids 部门编号数组
+     * @return 部门列表
+     */
+    List<SysDeptDO> listDepts(Collection<Long> ids);
+
     /**
      * 筛选部门列表
      *
@@ -27,4 +41,13 @@ public interface SysDeptService {
      */
     List<SysDeptDO> listDepts(SysDeptListReqVO reqVO);
 
+    /**
+     * 获得所有子部门,从缓存中
+     *
+     * @param parentId 部门编号
+     * @param recursive 是否递归获取所有
+     * @return 子部门列表
+     */
+    List<SysDeptDO> listDeptsByParentIdFromCache(Long parentId, boolean recursive);
+
 }

+ 84 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java

@@ -1,13 +1,22 @@
 package cn.iocoder.dashboard.modules.system.service.dept.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dept.SysDeptMapper;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO;
 import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 部门 Service 实现类
@@ -15,19 +24,94 @@ import java.util.List;
  * @author 芋道源码
  */
 @Service
+@Slf4j
 public class SysDeptServiceImpl implements SysDeptService {
 
+    /**
+     * 部门缓存
+     * key:部门编号 {@link SysDeptDO#getId()}
+     *
+     * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
+     */
+    private volatile Map<Long, SysDeptDO> deptCache;
+    /**
+     * 父部门缓存
+     * key:部门编号 {@link SysDeptDO#getParentId()}
+     * value: 直接子部门列表
+     *
+     * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
+     */
+    private volatile Multimap<Long, SysDeptDO> parentDeptCache;
+
     @Resource
     private SysDeptMapper deptMapper;
 
+    @Override
+    @PostConstruct
+    public void init() {
+        // 从数据库中读取
+        List<SysDeptDO> sysDeptDOList = deptMapper.selectList();
+        // 构建缓存
+        ImmutableMap.Builder<Long, SysDeptDO> builder = ImmutableMap.builder();
+        ImmutableMultimap.Builder<Long, SysDeptDO> parentBuilder = ImmutableMultimap.builder();
+        sysDeptDOList.forEach(sysRoleDO -> {
+            builder.put(sysRoleDO.getId(), sysRoleDO);
+            parentBuilder.put(sysRoleDO.getParentId(), sysRoleDO);
+        });
+        // 设置缓存
+        deptCache = builder.build();
+        parentDeptCache = parentBuilder.build();
+        log.info("[init][初始化 Dept 数量为 {}]", sysDeptDOList.size());
+    }
+
     @Override
     public List<SysDeptDO> listDepts() {
         return deptMapper.selectList();
     }
 
+    @Override
+    public List<SysDeptDO> listDepts(Collection<Long> ids) {
+        return deptMapper.selectBatchIds(ids);
+    }
+
     @Override
     public List<SysDeptDO> listDepts(SysDeptListReqVO reqVO) {
         return deptMapper.selectList(reqVO);
     }
 
+    @Override
+    public List<SysDeptDO> listDeptsByParentIdFromCache(Long parentId, boolean recursive) {
+        List<SysDeptDO> result = new ArrayList<>();
+        // 递归,简单粗暴
+        this.listDeptsByParentIdFromCache(result, parentId,
+                recursive ? Integer.MAX_VALUE : 1, // 如果递归获取,则无限;否则,只递归 1 次
+                parentDeptCache);
+        return result;
+    }
+
+    /**
+     * 递归获取所有的子部门,添加到 result 结果
+     *
+     * @param result 结果
+     * @param parentId 父编号
+     * @param recursiveCount 递归次数
+     * @param parentDeptMap 父部门 Map,使用缓存,避免变化
+     */
+    private void listDeptsByParentIdFromCache(List<SysDeptDO> result, Long parentId, int recursiveCount,
+                                              Multimap<Long, SysDeptDO> parentDeptMap) {
+        // 递归次数为 0,结束!
+        if (recursiveCount == 0) {
+            return;
+        }
+        // 获得子部门
+        Collection<SysDeptDO> depts = parentDeptMap.get(parentId);
+        if (CollUtil.isEmpty(depts)) {
+            return;
+        }
+        result.addAll(depts);
+        // 继续递归
+        depts.forEach(dept -> listDeptsByParentIdFromCache(result, dept.getId(),
+                recursiveCount - 1, parentDeptMap));
+    }
+
 }

+ 6 - 6
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java

@@ -37,12 +37,6 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
 @Slf4j
 public class SysRoleServiceImpl implements SysRoleService {
 
-    @Resource
-    private SysPermissionService permissionService;
-
-    @Resource
-    private SysRoleMapper roleMapper;
-
     /**
      * 角色缓存
      * key:角色编号 {@link SysRoleDO#getId()}
@@ -51,6 +45,12 @@ public class SysRoleServiceImpl implements SysRoleService {
      */
     private volatile Map<Long, SysRoleDO> roleCache;
 
+    @Resource
+    private SysPermissionService permissionService;
+
+    @Resource
+    private SysRoleMapper roleMapper;
+
     /**
      * 初始化 {@link #roleCache} 缓存
      */

+ 11 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java

@@ -1,11 +1,13 @@
 package cn.iocoder.dashboard.modules.system.service.user;
 
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageReqVO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
 
 /**
  * 用户 Service 接口
  *
- * @author ruoyi
+ * @author 芋道源码
  */
 public interface SysUserService {
 //    /**
@@ -32,6 +34,14 @@ public interface SysUserService {
      */
     SysUserDO getUser(Long userId);
 
+    /**
+     * 获得用户分页列表
+     *
+     * @param reqVO 分页条件
+     * @return 分页列表
+     */
+    PageResult<SysUserDO> pageUsers(SysUserPageReqVO reqVO);
+
 //
 //    /**
 //     * 根据用户ID查询用户所属角色组

+ 26 - 2
src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java

@@ -1,17 +1,25 @@
 package cn.iocoder.dashboard.modules.system.service.user;
 
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserPageReqVO;
+import cn.iocoder.dashboard.modules.system.convert.user.SysUserConvert;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dao.user.SysUserMapper;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
+import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService;
+import cn.iocoder.dashboard.util.collection.CollectionUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
 
 
 /**
- * 用户 业务层处理
+ * 用户 Service 实现类
  *
- * @author ruoyi
+ * @author 芋道源码
  */
 @Service
 @Slf4j
@@ -20,6 +28,9 @@ public class SysUserServiceImpl implements SysUserService {
     @Resource
     private SysUserMapper userMapper;
 
+    @Resource
+    private SysDeptService deptService;
+
 //    @Autowired
 //    private SysUserMapper userMapper;
 //
@@ -61,6 +72,19 @@ public class SysUserServiceImpl implements SysUserService {
         return userMapper.selectById(userId);
     }
 
+    @Override
+    public PageResult<SysUserDO> pageUsers(SysUserPageReqVO reqVO) {
+        // 处理部门查询条件
+        List<Long> deptIds = Collections.emptyList();
+        if (reqVO.getDeptId() != null) {
+            deptIds = CollectionUtils.convertList(deptService.listDeptsByParentIdFromCache(reqVO.getDeptId(), true),
+                    SysDeptDO::getId);
+            deptIds.add(reqVO.getDeptId());
+        }
+        // 执行查询
+        return SysUserConvert.INSTANCE.convertPage(userMapper.selectList(reqVO, deptIds));
+    }
+
 //    /**
 //     * 通过用户ID查询用户
 //     *