ye-zhaojia 2 недель назад
Родитель
Сommit
284f79e899
20 измененных файлов с 202 добавлено и 32 удалено
  1. 2 0
      src/main/java/com/qqflow/engine/common/util/JwtUtils.java
  2. 1 0
      src/main/java/com/qqflow/engine/config/security/LoginUser.java
  3. 6 3
      src/main/java/com/qqflow/engine/domain/flow/controller/ApprovalTaskController.java
  4. 2 0
      src/main/java/com/qqflow/engine/domain/flow/mapper/ApprovalTaskMapper.java
  5. 3 3
      src/main/java/com/qqflow/engine/domain/flow/service/ApprovalTaskService.java
  6. 17 9
      src/main/java/com/qqflow/engine/domain/flow/service/impl/ApprovalTaskServiceImpl.java
  7. 21 5
      src/main/java/com/qqflow/engine/domain/flow/service/impl/FlowEngineServiceImpl.java
  8. 34 2
      src/main/java/com/qqflow/engine/domain/system/controller/AuthController.java
  9. 3 0
      src/main/java/com/qqflow/engine/domain/system/dto/LoginDTO.java
  10. 4 0
      src/main/java/com/qqflow/engine/domain/system/dto/RoleDTO.java
  11. 3 0
      src/main/java/com/qqflow/engine/domain/system/dto/UserDTO.java
  12. 8 0
      src/main/java/com/qqflow/engine/domain/system/entity/SysRole.java
  13. 7 0
      src/main/java/com/qqflow/engine/domain/system/mapper/SysRoleMapper.java
  14. 49 0
      src/main/java/com/qqflow/engine/domain/system/service/RoleAuthService.java
  15. 14 0
      src/main/java/com/qqflow/engine/domain/system/service/impl/SysRoleServiceImpl.java
  16. 1 0
      src/main/java/com/qqflow/engine/domain/system/service/impl/SysUserServiceImpl.java
  17. 6 5
      src/main/resources/data-dev.sql
  18. 16 0
      src/main/resources/mapper/flow/ApprovalTaskMapper.xml
  19. 1 1
      src/main/resources/mapper/system/SysRoleMapper.xml
  20. 4 4
      src/main/resources/schema-dev.sql

+ 2 - 0
src/main/java/com/qqflow/engine/common/util/JwtUtils.java

@@ -38,6 +38,7 @@ public class JwtUtils {
                 .claim("realName", loginUser.getRealName())
                 .claim("realName", loginUser.getRealName())
                 .claim("deptId", loginUser.getDeptId())
                 .claim("deptId", loginUser.getDeptId())
                 .claim("employeeType", loginUser.getEmployeeType())
                 .claim("employeeType", loginUser.getEmployeeType())
+                .claim("userType", loginUser.getUserType())
                 .claim("permissions", loginUser.getPermissions())
                 .claim("permissions", loginUser.getPermissions())
                 .claim("roles", loginUser.getRoles())
                 .claim("roles", loginUser.getRoles())
                 .issuedAt(now)
                 .issuedAt(now)
@@ -71,6 +72,7 @@ public class JwtUtils {
         user.setRealName(claims.get("realName", String.class));
         user.setRealName(claims.get("realName", String.class));
         user.setDeptId(claims.get("deptId", Long.class));
         user.setDeptId(claims.get("deptId", Long.class));
         user.setEmployeeType(claims.get("employeeType", String.class));
         user.setEmployeeType(claims.get("employeeType", String.class));
+        user.setUserType(claims.get("userType", String.class));
         List<String> perms = claims.get("permissions", List.class);
         List<String> perms = claims.get("permissions", List.class);
         user.setPermissions(perms != null ? new java.util.HashSet<>(perms) : null);
         user.setPermissions(perms != null ? new java.util.HashSet<>(perms) : null);
         List<String> roles = claims.get("roles", List.class);
         List<String> roles = claims.get("roles", List.class);

+ 1 - 0
src/main/java/com/qqflow/engine/config/security/LoginUser.java

@@ -19,6 +19,7 @@ public class LoginUser implements UserDetails {
     private String realName;
     private String realName;
     private Long deptId;
     private Long deptId;
     private String employeeType;
     private String employeeType;
+    private String userType; // SYSTEM / ROLE
     private Set<String> permissions;
     private Set<String> permissions;
     private List<String> roles;
     private List<String> roles;
 
 

+ 6 - 3
src/main/java/com/qqflow/engine/domain/flow/controller/ApprovalTaskController.java

@@ -37,7 +37,8 @@ public class ApprovalTaskController {
             @RequestParam(defaultValue = "10") Integer pageSize,
             @RequestParam(defaultValue = "10") Integer pageSize,
             @RequestParam(required = false) String processName) {
             @RequestParam(required = false) String processName) {
         Long assigneeId = SecurityUtils.getUserId();
         Long assigneeId = SecurityUtils.getUserId();
-        return Result.ok(this.approvalTaskService.todoList(assigneeId, processName, pageNum, pageSize));
+        String assigneeType = SecurityUtils.getLoginUser().getUserType();
+        return Result.ok(this.approvalTaskService.todoList(assigneeId, assigneeType, processName, pageNum, pageSize));
     }
     }
 
 
     @GetMapping("/handled")
     @GetMapping("/handled")
@@ -47,7 +48,8 @@ public class ApprovalTaskController {
             @RequestParam(defaultValue = "10") Integer pageSize,
             @RequestParam(defaultValue = "10") Integer pageSize,
             @RequestParam(required = false) String processName) {
             @RequestParam(required = false) String processName) {
         Long assigneeId = SecurityUtils.getUserId();
         Long assigneeId = SecurityUtils.getUserId();
-        return Result.ok(this.approvalTaskService.handledList(assigneeId, processName, pageNum, pageSize));
+        String assigneeType = SecurityUtils.getLoginUser().getUserType();
+        return Result.ok(this.approvalTaskService.handledList(assigneeId, assigneeType, processName, pageNum, pageSize));
     }
     }
 
 
     @PostMapping("/{taskId}/approve")
     @PostMapping("/{taskId}/approve")
@@ -99,6 +101,7 @@ public class ApprovalTaskController {
     @Operation(summary = "我的待办任务数")
     @Operation(summary = "我的待办任务数")
     public Result<Long> todoCount() {
     public Result<Long> todoCount() {
         Long assigneeId = SecurityUtils.getUserId();
         Long assigneeId = SecurityUtils.getUserId();
-        return Result.ok(this.approvalTaskService.todoCount(assigneeId));
+        String assigneeType = SecurityUtils.getLoginUser().getUserType();
+        return Result.ok(this.approvalTaskService.todoCount(assigneeId, assigneeType));
     }
     }
 }
 }

+ 2 - 0
src/main/java/com/qqflow/engine/domain/flow/mapper/ApprovalTaskMapper.java

@@ -34,10 +34,12 @@ public interface ApprovalTaskMapper extends BaseMapper<ApprovalTask> {
     com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> selectTodoList(
     com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> selectTodoList(
             com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> page,
             com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> page,
             @Param("assigneeId") Long assigneeId,
             @Param("assigneeId") Long assigneeId,
+            @Param("assigneeType") String assigneeType,
             @Param("processName") String processName);
             @Param("processName") String processName);
 
 
     com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> selectHandledList(
     com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> selectHandledList(
             com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> page,
             com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> page,
             @Param("assigneeId") Long assigneeId,
             @Param("assigneeId") Long assigneeId,
+            @Param("assigneeType") String assigneeType,
             @Param("processName") String processName);
             @Param("processName") String processName);
 }
 }

+ 3 - 3
src/main/java/com/qqflow/engine/domain/flow/service/ApprovalTaskService.java

@@ -10,9 +10,9 @@ import java.util.List;
 
 
 public interface ApprovalTaskService {
 public interface ApprovalTaskService {
 
 
-    PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String processName, Integer pageNum, Integer pageSize);
+    PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String assigneeType, String processName, Integer pageNum, Integer pageSize);
 
 
-    PageResult<ApprovalTaskDTO> handledList(Long assigneeId, String processName, Integer pageNum, Integer pageSize);
+    PageResult<ApprovalTaskDTO> handledList(Long assigneeId, String assigneeType, String processName, Integer pageNum, Integer pageSize);
 
 
     void approve(ApproveTaskDTO dto);
     void approve(ApproveTaskDTO dto);
 
 
@@ -26,5 +26,5 @@ public interface ApprovalTaskService {
 
 
     List<ApprovalRecordDTO> history(Long instanceId);
     List<ApprovalRecordDTO> history(Long instanceId);
 
 
-    Long todoCount(Long assigneeId);
+    Long todoCount(Long assigneeId, String assigneeType);
 }
 }

+ 17 - 9
src/main/java/com/qqflow/engine/domain/flow/service/impl/ApprovalTaskServiceImpl.java

@@ -45,9 +45,9 @@ public class ApprovalTaskServiceImpl implements ApprovalTaskService {
     private final ApplicationEventPublisher eventPublisher;
     private final ApplicationEventPublisher eventPublisher;
 
 
     @Override
     @Override
-    public PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String processName, Integer pageNum, Integer pageSize) {
+    public PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String assigneeType, String processName, Integer pageNum, Integer pageSize) {
         Page<ApprovalTask> page = new Page<>(pageNum, pageSize);
         Page<ApprovalTask> page = new Page<>(pageNum, pageSize);
-        this.approvalTaskMapper.selectTodoList(page, assigneeId, processName);
+        this.approvalTaskMapper.selectTodoList(page, assigneeId, assigneeType, processName);
         List<ApprovalTaskDTO> records = page.getRecords().stream()
         List<ApprovalTaskDTO> records = page.getRecords().stream()
                 .map(ApprovalTaskDTO::of)
                 .map(ApprovalTaskDTO::of)
                 .collect(Collectors.toList());
                 .collect(Collectors.toList());
@@ -55,9 +55,9 @@ public class ApprovalTaskServiceImpl implements ApprovalTaskService {
     }
     }
 
 
     @Override
     @Override
-    public PageResult<ApprovalTaskDTO> handledList(Long assigneeId, String processName, Integer pageNum, Integer pageSize) {
+    public PageResult<ApprovalTaskDTO> handledList(Long assigneeId, String assigneeType, String processName, Integer pageNum, Integer pageSize) {
         Page<ApprovalTask> page = new Page<>(pageNum, pageSize);
         Page<ApprovalTask> page = new Page<>(pageNum, pageSize);
-        this.approvalTaskMapper.selectHandledList(page, assigneeId, processName);
+        this.approvalTaskMapper.selectHandledList(page, assigneeId, assigneeType, processName);
         List<ApprovalTaskDTO> records = page.getRecords().stream()
         List<ApprovalTaskDTO> records = page.getRecords().stream()
                 .map(ApprovalTaskDTO::of)
                 .map(ApprovalTaskDTO::of)
                 .collect(Collectors.toList());
                 .collect(Collectors.toList());
@@ -132,11 +132,19 @@ public class ApprovalTaskServiceImpl implements ApprovalTaskService {
     }
     }
 
 
     @Override
     @Override
-    public Long todoCount(Long assigneeId) {
-        return this.approvalTaskMapper.selectCount(
-                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalTask>()
-                        .eq(ApprovalTask::getAssigneeId, assigneeId)
-                        .eq(ApprovalTask::getTaskStatus, TaskStatus.PENDING.getCode()));
+    public Long todoCount(Long assigneeId, String assigneeType) {
+        com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalTask> wrapper =
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalTask>();
+        wrapper.eq(ApprovalTask::getAssigneeId, assigneeId)
+                .eq(ApprovalTask::getTaskStatus, TaskStatus.PENDING.getCode());
+        if ("ROLE".equals(assigneeType)) {
+            wrapper.eq(ApprovalTask::getAssigneeType, "ROLE");
+        } else {
+            wrapper.and(w -> w.isNull(ApprovalTask::getAssigneeType)
+                    .or().eq(ApprovalTask::getAssigneeType, "")
+                    .or().eq(ApprovalTask::getAssigneeType, "USER"));
+        }
+        return this.approvalTaskMapper.selectCount(wrapper);
     }
     }
 
 
     private ApprovalTask getPendingTask(Long taskId) {
     private ApprovalTask getPendingTask(Long taskId) {

+ 21 - 5
src/main/java/com/qqflow/engine/domain/flow/service/impl/FlowEngineServiceImpl.java

@@ -155,10 +155,8 @@ public class FlowEngineServiceImpl implements FlowEngineService {
             if (role == null) {
             if (role == null) {
                 return Collections.emptyList();
                 return Collections.emptyList();
             }
             }
-            List<SysUserRole> userRoles = this.sysUserRoleMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysUserRole>()
-                            .eq(SysUserRole::getRoleId, role.getId()));
-            return userRoles.stream().map(SysUserRole::getUserId).distinct().collect(Collectors.toList());
+            // 角色用户独立登录,直接返回角色ID
+            return Collections.singletonList(role.getId());
         }
         }
         if ("LEADER".equals(assigneeType)) {
         if ("LEADER".equals(assigneeType)) {
             SysUser applicant = this.sysUserMapper.selectById(instance.getApplicantId());
             SysUser applicant = this.sysUserMapper.selectById(instance.getApplicantId());
@@ -282,10 +280,28 @@ public class FlowEngineServiceImpl implements FlowEngineService {
             if ("or".equals(approveMode) && assignees.size() > 1) {
             if ("or".equals(approveMode) && assignees.size() > 1) {
                 finalAssignees = assignees;
                 finalAssignees = assignees;
             }
             }
+            // 确定处理人类型
+            Map<String, Object> nodeProps = node.getProperties();
+            String taskAssigneeType = "USER";
+            if (nodeProps != null) {
+                Object typeObj = nodeProps.get("assigneeType");
+                if (typeObj != null) {
+                    taskAssigneeType = typeObj.toString();
+                } else {
+                    Object approverObj = nodeProps.get("approver");
+                    if (approverObj != null) {
+                        taskAssigneeType = "ROLE";
+                    }
+                }
+            }
+            // SELF/LEADER 已解析为具体用户ID,assigneeType 设为 USER
+            if ("SELF".equals(taskAssigneeType) || "LEADER".equals(taskAssigneeType)) {
+                taskAssigneeType = "USER";
+            }
             for (Long assigneeId : finalAssignees) {
             for (Long assigneeId : finalAssignees) {
                 ApprovalTask task = this.approvalTaskAssembler.buildNew(
                 ApprovalTask task = this.approvalTaskAssembler.buildNew(
                         instance.getId(), node.getId(), node.getName(),
                         instance.getId(), node.getId(), node.getName(),
-                        node.getType(), assigneeId, "USER", TaskStatus.PENDING.getCode()
+                        node.getType(), assigneeId, taskAssigneeType, TaskStatus.PENDING.getCode()
                 );
                 );
                 this.approvalTaskMapper.insert(task);
                 this.approvalTaskMapper.insert(task);
             }
             }

+ 34 - 2
src/main/java/com/qqflow/engine/domain/system/controller/AuthController.java

@@ -7,6 +7,9 @@ import com.qqflow.engine.domain.system.assembler.UserAssembler;
 import com.qqflow.engine.domain.system.dto.LoginDTO;
 import com.qqflow.engine.domain.system.dto.LoginDTO;
 import com.qqflow.engine.domain.system.dto.UserDTO;
 import com.qqflow.engine.domain.system.dto.UserDTO;
 import com.qqflow.engine.domain.system.entity.SysUser;
 import com.qqflow.engine.domain.system.entity.SysUser;
+import com.qqflow.engine.domain.system.entity.SysRole;
+import com.qqflow.engine.domain.system.mapper.SysRoleMapper;
+import com.qqflow.engine.domain.system.service.RoleAuthService;
 import com.qqflow.engine.domain.system.service.SysUserService;
 import com.qqflow.engine.domain.system.service.SysUserService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -25,11 +28,20 @@ public class AuthController {
 
 
     @Resource
     @Resource
     private SysUserService sysUserService;
     private SysUserService sysUserService;
+    @Resource
+    private RoleAuthService roleAuthService;
+    @Resource
+    private SysRoleMapper sysRoleMapper;
 
 
     @Operation(summary = "用户登录")
     @Operation(summary = "用户登录")
     @PostMapping("/login")
     @PostMapping("/login")
     public Result<Map<String, String>> login(@Valid @RequestBody LoginDTO loginDTO) {
     public Result<Map<String, String>> login(@Valid @RequestBody LoginDTO loginDTO) {
-        String token = sysUserService.login(loginDTO);
+        String token;
+        if ("ROLE".equals(loginDTO.getLoginType())) {
+            token = roleAuthService.login(loginDTO);
+        } else {
+            token = sysUserService.login(loginDTO);
+        }
         Map<String, String> map = new HashMap<>();
         Map<String, String> map = new HashMap<>();
         map.put("token", token);
         map.put("token", token);
         return Result.ok(map);
         return Result.ok(map);
@@ -60,7 +72,27 @@ public class AuthController {
         if (loginUser == null) {
         if (loginUser == null) {
             return Result.error(401, "未登录");
             return Result.error(401, "未登录");
         }
         }
+        if ("ROLE".equals(loginUser.getUserType())) {
+            SysRole role = sysRoleMapper.selectById(loginUser.getUserId());
+            if (role == null) {
+                return Result.error(401, "用户不存在");
+            }
+            UserDTO dto = new UserDTO();
+            dto.setId(role.getId());
+            dto.setUsername(role.getUsername());
+            dto.setRealName(role.getRoleName());
+            dto.setDeptId(role.getDeptId());
+            dto.setStatus(role.getStatus());
+            dto.setCreateTime(role.getCreateTime());
+            dto.setRoles(loginUser.getRoles());
+            dto.setUserType("ROLE");
+            return Result.ok(dto);
+        }
         SysUser user = sysUserService.getByUsername(loginUser.getUsername());
         SysUser user = sysUserService.getByUsername(loginUser.getUsername());
-        return Result.ok(UserAssembler.toDTO(user));
+        UserDTO dto = UserAssembler.toDTO(user);
+        if (dto != null) {
+            dto.setUserType("SYSTEM");
+        }
+        return Result.ok(dto);
     }
     }
 }
 }

+ 3 - 0
src/main/java/com/qqflow/engine/domain/system/dto/LoginDTO.java

@@ -15,4 +15,7 @@ public class LoginDTO {
     @NotBlank(message = "密码不能为空")
     @NotBlank(message = "密码不能为空")
     @Schema(description = "密码")
     @Schema(description = "密码")
     private String password;
     private String password;
+
+    @Schema(description = "登录类型:SYSTEM-系统用户 ROLE-角色用户")
+    private String loginType;
 }
 }

+ 4 - 0
src/main/java/com/qqflow/engine/domain/system/dto/RoleDTO.java

@@ -19,6 +19,9 @@ public class RoleDTO {
     @Schema(description = "角色名称")
     @Schema(description = "角色名称")
     private String roleName;
     private String roleName;
 
 
+    @Schema(description = "登录账号")
+    private String username;
+
     @Schema(description = "角色范围")
     @Schema(description = "角色范围")
     private String roleScope;
     private String roleScope;
 
 
@@ -45,6 +48,7 @@ public class RoleDTO {
         dto.setId(role.getId());
         dto.setId(role.getId());
         dto.setRoleCode(role.getRoleCode());
         dto.setRoleCode(role.getRoleCode());
         dto.setRoleName(role.getRoleName());
         dto.setRoleName(role.getRoleName());
+        dto.setUsername(role.getUsername());
         dto.setRoleScope(role.getRoleScope());
         dto.setRoleScope(role.getRoleScope());
         dto.setParentId(role.getParentId());
         dto.setParentId(role.getParentId());
         dto.setDeptId(role.getDeptId());
         dto.setDeptId(role.getDeptId());

+ 3 - 0
src/main/java/com/qqflow/engine/domain/system/dto/UserDTO.java

@@ -44,6 +44,9 @@ public class UserDTO {
     @Schema(description = "角色列表")
     @Schema(description = "角色列表")
     private List<String> roles;
     private List<String> roles;
 
 
+    @Schema(description = "用户类型:SYSTEM-系统用户 ROLE-角色用户")
+    private String userType;
+
     public static UserDTO of(SysUser user) {
     public static UserDTO of(SysUser user) {
         if (user == null) {
         if (user == null) {
             return null;
             return null;

+ 8 - 0
src/main/java/com/qqflow/engine/domain/system/entity/SysRole.java

@@ -3,6 +3,7 @@ package com.qqflow.engine.domain.system.entity;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.Data;
 
 
@@ -32,6 +33,13 @@ public class SysRole {
     @Schema(description = "所属部门ID")
     @Schema(description = "所属部门ID")
     private Long deptId;
     private Long deptId;
 
 
+    @Schema(description = "登录账号")
+    private String username;
+
+    @JsonIgnore
+    @Schema(description = "密码")
+    private String password;
+
     @Schema(description = "状态:0-禁用 1-正常")
     @Schema(description = "状态:0-禁用 1-正常")
     private Integer status;
     private Integer status;
 
 

+ 7 - 0
src/main/java/com/qqflow/engine/domain/system/mapper/SysRoleMapper.java

@@ -15,5 +15,12 @@ public interface SysRoleMapper extends BaseMapper<SysRole> {
         );
         );
     }
     }
 
 
+    default SysRole selectByUsername(String username) {
+        return this.selectOne(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysRole>()
+                        .eq(SysRole::getUsername, username)
+        );
+    }
+
     List<SysRole> selectRolesByUserId(@Param("userId") Long userId);
     List<SysRole> selectRolesByUserId(@Param("userId") Long userId);
 }
 }

+ 49 - 0
src/main/java/com/qqflow/engine/domain/system/service/RoleAuthService.java

@@ -0,0 +1,49 @@
+package com.qqflow.engine.domain.system.service;
+
+import com.qqflow.engine.common.exception.BusinessException;
+import com.qqflow.engine.common.util.JwtUtils;
+import com.qqflow.engine.config.security.LoginUser;
+import com.qqflow.engine.domain.system.dto.LoginDTO;
+import com.qqflow.engine.domain.system.entity.SysRole;
+import com.qqflow.engine.domain.system.mapper.SysRoleMapper;
+import jakarta.annotation.Resource;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Set;
+
+@Service
+public class RoleAuthService {
+
+    @Resource
+    private SysRoleMapper sysRoleMapper;
+    @Resource
+    private PasswordEncoder passwordEncoder;
+    @Resource
+    private JwtUtils jwtUtils;
+
+    public String login(LoginDTO loginDTO) {
+        SysRole role = sysRoleMapper.selectByUsername(loginDTO.getUsername());
+        if (role == null || role.getStatus() == null || role.getStatus() != 1) {
+            throw new BusinessException("用户名或密码错误");
+        }
+        if (!passwordEncoder.matches(loginDTO.getPassword(), role.getPassword())) {
+            throw new BusinessException("用户名或密码错误");
+        }
+        LoginUser loginUser = new LoginUser();
+        loginUser.setUserId(role.getId());
+        loginUser.setUsername(role.getUsername());
+        loginUser.setRealName(role.getRoleName());
+        loginUser.setUserType("ROLE");
+        loginUser.setPermissions(Set.of(
+                "flow:task:todo",
+                "flow:task:handled",
+                "flow:task:approve",
+                "flow:task:reject",
+                "flow:instance:mine"
+        ));
+        loginUser.setRoles(List.of(role.getRoleCode()));
+        return jwtUtils.generateToken(loginUser);
+    }
+}

+ 14 - 0
src/main/java/com/qqflow/engine/domain/system/service/impl/SysRoleServiceImpl.java

@@ -13,7 +13,9 @@ import com.qqflow.engine.domain.system.mapper.SysRoleMenuMapper;
 import com.qqflow.engine.domain.system.mapper.SysUserRoleMapper;
 import com.qqflow.engine.domain.system.mapper.SysUserRoleMapper;
 import com.qqflow.engine.domain.system.service.SysRoleService;
 import com.qqflow.engine.domain.system.service.SysRoleService;
 import jakarta.annotation.Resource;
 import jakarta.annotation.Resource;
+import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
 
 
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.ArrayList;
@@ -34,14 +36,26 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole>
     @Resource
     @Resource
     private SysDeptMapper sysDeptMapper;
     private SysDeptMapper sysDeptMapper;
 
 
+    @Resource
+    private PasswordEncoder passwordEncoder;
+
     @Override
     @Override
     public boolean addRole(SysRole role) {
     public boolean addRole(SysRole role) {
         role.setCreateTime(LocalDateTime.now());
         role.setCreateTime(LocalDateTime.now());
+        if (StringUtils.hasText(role.getPassword())) {
+            role.setPassword(passwordEncoder.encode(role.getPassword()));
+        }
         return this.save(role);
         return this.save(role);
     }
     }
 
 
     @Override
     @Override
     public boolean updateRole(SysRole role) {
     public boolean updateRole(SysRole role) {
+        if (StringUtils.hasText(role.getPassword())) {
+            role.setPassword(passwordEncoder.encode(role.getPassword()));
+        } else {
+            // 不修改密码时,清空 password 字段避免覆盖
+            role.setPassword(null);
+        }
         return this.updateById(role);
         return this.updateById(role);
     }
     }
 
 

+ 1 - 0
src/main/java/com/qqflow/engine/domain/system/service/impl/SysUserServiceImpl.java

@@ -244,6 +244,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
         loginUser.setRealName(user.getRealName());
         loginUser.setRealName(user.getRealName());
         loginUser.setDeptId(user.getDeptId());
         loginUser.setDeptId(user.getDeptId());
         loginUser.setEmployeeType(user.getEmployeeType());
         loginUser.setEmployeeType(user.getEmployeeType());
+        loginUser.setUserType("SYSTEM");
         loginUser.setPassword(user.getPassword());
         loginUser.setPassword(user.getPassword());
         loginUser.setPermissions(this.loadUserPermissions(user.getId()));
         loginUser.setPermissions(this.loadUserPermissions(user.getId()));
         loginUser.setRoles(this.loadUserRoles(user.getId()));
         loginUser.setRoles(this.loadUserRoles(user.getId()));

+ 6 - 5
src/main/resources/data-dev.sql

@@ -12,11 +12,11 @@ MERGE INTO sys_user (id, username, password, real_name, phone, email, dept_id, e
 (3, 'lisi', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', '李四', '13800138002', 'lisi@qqflow.com', 3, 'dept_manager', 0),
 (3, 'lisi', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', '李四', '13800138002', 'lisi@qqflow.com', 3, 'dept_manager', 0),
 (4, 'wangwu', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', '王五', '13800138003', 'wangwu@qqflow.com', 4, 'flow_manager', 0);
 (4, 'wangwu', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', '王五', '13800138003', 'wangwu@qqflow.com', 4, 'flow_manager', 0);
 
 
-MERGE INTO sys_role (id, role_code, role_name, role_scope, parent_id, dept_id, status) KEY(id) VALUES
-(1, 'super_admin', '超级管理员', 'platform', 0, 1, 1),
-(2, 'flow_admin', '流程管理员', 'tenant', 0, 1, 1),
-(3, 'normal_user', '普通用户', 'tenant', 0, 2, 1),
-(4, 'dept_manager', '部门经理', 'tenant', 3, 3, 1);
+MERGE INTO sys_role (id, role_code, role_name, role_scope, parent_id, dept_id, username, password, status) KEY(id) VALUES
+(1, 'super_admin', '超级管理员', 'platform', 0, 1, 'role_super_admin', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', 1),
+(2, 'flow_admin', '流程管理员', 'tenant', 0, 1, 'role_flow_admin', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', 1),
+(3, 'normal_user', '普通用户', 'tenant', 0, 2, 'role_normal_user', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', 1),
+(4, 'dept_manager', '部门经理', 'tenant', 3, 3, 'role_dept_manager', '$2a$10$Wnh8Jnt2AGHNNu1XTyyNveqkXvE1BnuzvHt1xS5AL3YdDif/7iXta', 1);
 
 
 MERGE INTO sys_menu (id, menu_name, menu_type, permission, parent_id, sort_order, component, icon, status) KEY(id) VALUES
 MERGE INTO sys_menu (id, menu_name, menu_type, permission, parent_id, sort_order, component, icon, status) KEY(id) VALUES
 (1, '系统管理', 0, NULL, 0, 1, NULL, 'Setting', 1),
 (1, '系统管理', 0, NULL, 0, 1, NULL, 'Setting', 1),
@@ -43,6 +43,7 @@ MERGE INTO sys_user_role (id, user_id, role_id) KEY(id) VALUES
 (3, 3, 3),
 (3, 3, 3),
 (4, 4, 3);
 (4, 4, 3);
 
 
+
 MERGE INTO sys_role_menu (id, role_id, menu_id) KEY(id) VALUES
 MERGE INTO sys_role_menu (id, role_id, menu_id) KEY(id) VALUES
 (1, 1, 1), (2, 1, 2), (3, 1, 3), (4, 1, 4), (5, 1, 5), (6, 1, 6), (7, 1, 7), (8, 1, 8), (9, 1, 9),
 (1, 1, 1), (2, 1, 2), (3, 1, 3), (4, 1, 4), (5, 1, 5), (6, 1, 6), (7, 1, 7), (8, 1, 8), (9, 1, 9),
 (10, 1, 10), (11, 1, 11), (12, 1, 12), (13, 1, 13), (14, 1, 14), (15, 1, 15), (16, 1, 16), (32, 1, 17),
 (10, 1, 10), (11, 1, 11), (12, 1, 12), (13, 1, 13), (14, 1, 14), (15, 1, 15), (16, 1, 16), (32, 1, 17),

+ 16 - 0
src/main/resources/mapper/flow/ApprovalTaskMapper.xml

@@ -31,6 +31,14 @@
         WHERE t.deleted = 0
         WHERE t.deleted = 0
           AND t.assignee_id = #{assigneeId}
           AND t.assignee_id = #{assigneeId}
           AND t.task_status = 0
           AND t.task_status = 0
+          <choose>
+              <when test="assigneeType == 'ROLE'">
+                  AND t.assignee_type = 'ROLE'
+              </when>
+              <otherwise>
+                  AND (t.assignee_type IS NULL OR t.assignee_type = '' OR t.assignee_type = 'USER')
+              </otherwise>
+          </choose>
         <if test="processName != null and processName != ''">
         <if test="processName != null and processName != ''">
             AND pd.process_name LIKE CONCAT('%', #{processName}, '%')
             AND pd.process_name LIKE CONCAT('%', #{processName}, '%')
         </if>
         </if>
@@ -45,6 +53,14 @@
         WHERE t.deleted = 0
         WHERE t.deleted = 0
           AND t.assignee_id = #{assigneeId}
           AND t.assignee_id = #{assigneeId}
           AND t.task_status IN (1, 2, 4)
           AND t.task_status IN (1, 2, 4)
+          <choose>
+              <when test="assigneeType == 'ROLE'">
+                  AND t.assignee_type = 'ROLE'
+              </when>
+              <otherwise>
+                  AND (t.assignee_type IS NULL OR t.assignee_type = '' OR t.assignee_type = 'USER')
+              </otherwise>
+          </choose>
         <if test="processName != null and processName != ''">
         <if test="processName != null and processName != ''">
             AND pd.process_name LIKE CONCAT('%', #{processName}, '%')
             AND pd.process_name LIKE CONCAT('%', #{processName}, '%')
         </if>
         </if>

+ 1 - 1
src/main/resources/mapper/system/SysRoleMapper.xml

@@ -3,7 +3,7 @@
 <mapper namespace="com.qqflow.engine.domain.system.mapper.SysRoleMapper">
 <mapper namespace="com.qqflow.engine.domain.system.mapper.SysRoleMapper">
 
 
     <select id="selectRolesByUserId" resultType="com.qqflow.engine.domain.system.entity.SysRole">
     <select id="selectRolesByUserId" resultType="com.qqflow.engine.domain.system.entity.SysRole">
-        SELECT r.id, r.role_code, r.role_name, r.role_scope, r.parent_id, r.status, r.create_time
+        SELECT r.id, r.role_code, r.role_name, r.role_scope, r.parent_id, r.dept_id, r.username, r.password, r.status, r.create_time
         FROM sys_role r
         FROM sys_role r
         INNER JOIN sys_user_role ur ON r.id = ur.role_id
         INNER JOIN sys_user_role ur ON r.id = ur.role_id
         WHERE ur.user_id = #{userId}
         WHERE ur.user_id = #{userId}

+ 4 - 4
src/main/resources/schema-dev.sql

@@ -19,12 +19,12 @@ CREATE TABLE IF NOT EXISTS sys_role (
     role_scope VARCHAR(20) DEFAULT 'tenant',
     role_scope VARCHAR(20) DEFAULT 'tenant',
     parent_id BIGINT DEFAULT 0,
     parent_id BIGINT DEFAULT 0,
     dept_id BIGINT DEFAULT 0,
     dept_id BIGINT DEFAULT 0,
+    username VARCHAR(50),
+    password VARCHAR(100),
     status TINYINT DEFAULT 1,
     status TINYINT DEFAULT 1,
     create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
 );
 );
 
 
-ALTER TABLE sys_role ADD COLUMN IF NOT EXISTS dept_id BIGINT DEFAULT 0;
-
 CREATE TABLE IF NOT EXISTS sys_menu (
 CREATE TABLE IF NOT EXISTS sys_menu (
     id BIGINT PRIMARY KEY AUTO_INCREMENT,
     id BIGINT PRIMARY KEY AUTO_INCREMENT,
     menu_name VARCHAR(50) NOT NULL,
     menu_name VARCHAR(50) NOT NULL,
@@ -90,7 +90,7 @@ CREATE TABLE IF NOT EXISTS bpm_process_instance (
     form_data TEXT,
     form_data TEXT,
     current_node_id VARCHAR(50),
     current_node_id VARCHAR(50),
     status TINYINT DEFAULT 0,
     status TINYINT DEFAULT 0,
-    result TINYINT,
+    result VARCHAR(20),
     start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     end_time TIMESTAMP,
     end_time TIMESTAMP,
     create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
@@ -107,7 +107,7 @@ CREATE TABLE IF NOT EXISTS bpm_approval_task (
     assignee_id BIGINT,
     assignee_id BIGINT,
     assignee_type VARCHAR(20),
     assignee_type VARCHAR(20),
     task_status TINYINT DEFAULT 0,
     task_status TINYINT DEFAULT 0,
-    approval_result TINYINT,
+    approval_result VARCHAR(20),
     approval_comment TEXT,
     approval_comment TEXT,
     attachment_urls TEXT,
     attachment_urls TEXT,
     timeout_time TIMESTAMP,
     timeout_time TIMESTAMP,