当前位置: 首页 > news >正文

Flowable7.x学习笔记(十六)分页查询我的待办

前言

        我的待办具体区分为3种情况,第一个就是办理人指定就是我,我可以直接审批;第二种就是我是候选人,我需要先拾取任务然后再办理;第三种是我是候选组,我需要切换到指定的角色去拾取任务再办理。如果任务已经拾取过,应该还要支持归还任务。

        接下来我从动作解析以及代码实现完整的实现整体的功能,需要说明的是文章中代码只有比较核心的代码,完整代码我会在文章结尾标明gitee仓库地址和分支。

一、任务拾取和归还

① 拾取

        拾取操作将某个任务从候选人/候选组池中分配给具体用户,使其成为该任务的受理人,认领后它将从候选池中移除。

        组任务分配:对于指定了“候选组”而非“受理人”的用户任务,不同用户可以竞相拾取,完成后再进行归还或流转。

        防止重复处理:一旦某人认领,其他候选人即不能再拾取,避免重复处理同一任务。

        工作量可见性:通过查询已认领任务,可以统计各人的工作量和进度。

② 归还

        归还操作则是将已认领的任务放回到候选池,取消当前用户的受理人身份,使任务重新回到候选组或候选用户队列中。

        任务重分配:当拾取任务的用户无法继续处理(例如休假、权限不足等),可归还让其他候选人再拾取。

        防止任务滞留:若一人长时间未处理,可自动或手动归还以避免流程阻塞。

        动态负载均衡:系统或管理员可根据当前负载情况,将任务归还后由空闲人员重新拾取,提升整体吞吐。

二、Feign接口

        由于我把Flowable单独设置为一个模块,所有查询用户信息比如角色列表,用户具体信息这些需要从别的模块通过feign接口rpc远程调用,如果架构和我一样可以参考,如果是单体服务可以直接本服务调用。

① 定义远程接口

        这里是要有两个接口,一个是根据用户ID查询角色ID列表;一个是根据用户ID查询用户信息;后续在查询我的待办任务时候会用到。

/*** 根据用户ID查询角色ID列表** @param userId 用户ID,可选参数,用于查询角色ID列表* @return 返回一个Result对象,其中包含用户的角色ID列表*/
@PostMapping("/systemClient/api/v1/user/queryRoleIdsByUserId")
Result<List<Long>> queryRoleIdsByUserId(@RequestParam(required = false , name = "userId") Long userId);/*** 根据用户ID查询用户信息** @param userId 用户ID,作为查询条件,用于定位特定的用户信息* @return 返回一个Result对象,其中包含查询到的Oauth2BasicUserVO用户信息*/
@PostMapping("/systemClient/api/v1/user/queryUserById")
Result<Oauth2BasicUserVO> queryUserById(@RequestParam(required = false , name = "userId") Long userId);

② 远程服务实现远程接口

Ⅰ 定义接口

/*** 根据用户ID查询角色ID列表** @param userId 用户ID,可选参数,如果未提供,则默认为null* @return 返回一个Result对象,其中包含角色ID列表*/
@PostMapping("/queryRoleIdsByUserId")
public Result<List<Long>> queryRoleIdsByUserId(@RequestParam(required = false, name = "userId") Long userId) {try {// 查询所有未删除的角色信息List<Long> roleIds = sysRoleService.queryRoleIdsByUserId(userId);// 返回成功结果return Result.success(roleIds);} catch (Exception e) {// 记录错误日志并返回错误结果log.error("查询所有角色失败,失败原因:{}", e.getMessage(), e);return Result.error("查询所有角色失败,失败原因:" + e.getMessage());}
}/*** 根据用户ID查询用户信息** @param userId 用户ID,可选参数,用于指定要查询的用户* @return 返回一个Result对象,其中包含查询到的用户信息*/
@PostMapping("/queryUserById")
public Result<Oauth2BasicUserVO> queryUserById(@RequestParam(required = false, name = "userId") Long userId) {try {// 查询所有未删除的角色信息Oauth2BasicUser oauth2BasicUser = oauth2BasicUserService.getById(userId);// 使用 Oauth2BasicUserStructMapper 转换输出结果Oauth2BasicUserVO oauth2BasicUserVO =Oauth2BasicUserStructMapper.INSTANCE.toApiVO(oauth2BasicUser);return Result.success(oauth2BasicUserVO);} catch (Exception e) {// 记录错误日志并返回错误结果log.error("根据用户ID查询用户信息失败,失败原因:{}", e.getMessage(), e);return Result.error("根据用户ID查询用户信息失败,失败原因:" + e.getMessage());}
}

Ⅱ 定义接口的服务

/*** 根据用户ID查询角色ID列表** @param userId 用户ID,用于查询角色信息* @return 返回一个包含用户所拥有的角色ID的列表如果用户没有关联任何角色,则返回空列表*/
List<Long> queryRoleIdsByUserId(Long userId);

Ⅲ 实现接口的服务

/*** 根据用户ID查询角色ID清单** @param userId 用户ID,用于查询角色ID* @return 用户的角色ID清单,如果用户没有角色或查询失败,则返回空列表*/
@Override
public List<Long> queryRoleIdsByUserId(Long userId) {// 参数判空if (userId == null) {return List.of();}try {// 根据用户ID查询用户角色绑定关系,并只获取角色ID字段List<SysUserRole> sysUserRoles = sysUserRoleService.lambdaQuery().select(SysUserRole::getRoleId)  // 只查询需要的字段.eq(SysUserRole::getUserId, userId).list();// 返回用户角色ID清单return sysUserRoles.stream().map(SysUserRole::getRoleId).toList();} catch (Exception e) {log.error("根据用户ID查询用户角色ID清单失败,失败原因:", e);}// 如果查询过程中出现异常,返回空列表return List.of();
}

三、我的待办接口

① 定义请求参数

        这里只需要简单的分页信息即可,我的信息直接从当前登陆人的session种获取。

package com.ceair.entity.request;import lombok.Data;import java.io.Serial;
import java.io.Serializable;/*** @author wangbaohai* @ClassName PageReq* @description: 分页请求参数* @date 2025年02月16日* @version: 1.0.0*/
@Data
public class PageReq implements Serializable {@Serialprivate static final long serialVersionUID = 1L;/*** 分页查询的页码和每页大小。** pageNo: 当前页码,默认为1。* pageSize: 每页显示的记录数,默认为10。*/private Long current = 1L;private Long size = 10L;}

② 定义响应参数

        每个参数的定义请参考代码中的字段注释吧,也不是页面都要展示,不过多一些以防后续要用。

package com.ceair.entity.vo;import lombok.Data;import java.io.Serial;
import java.io.Serializable;
import java.util.List;/*** @author wangbaohai* @ClassName TaskListInfoVO* @description: 任务列表信息VO* @date 2025年04月30日* @version: 1.0.0*/
@Data
public class TaskListInfoVO implements Serializable {@Serialprivate static final long serialVersionUID = 1L;// 任务清单List<TaskVO> taskList;// 任务总数Long taskCount;}

package com.ceair.entity.vo;import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.flowable.variable.api.persistence.entity.VariableInstance;
import org.springframework.format.annotation.DateTimeFormat;import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Map;/*** @author wangbaohai* @ClassName TaskVO* @description: 任务实体VO* @date 2025年04月30日* @version: 1.0.0*/
@Data
public class TaskVO implements Serializable {@Serialprivate static final long serialVersionUID = 1L;// 任务编号private String taskId;// 任务执行编号private String executionId;// 任务名称private String taskName;//  任务Keyprivate String taskDefKey;// 任务执行人Idprivate String assigneeId;// 任务执行人名称private String assigneeName;// 流程发起人Idprivate String startUserId;// 流程发起人名称private String startUserName;// 流程类型private String category;// 流程变量信息private Object procVars;// 局部变量信息private Object taskLocalVars;// 流程部署编号private String deployId;// 流程IDprivate String procDefId;// 流程keyprivate String procDefKey;// 流程定义名称private String procDefName;// 流程定义内置使用版本private int procDefVersion;// 流程实例IDprivate String procInsId;// 历史流程实例IDprivate String hisProcInsId;// 任务耗时private String duration;// 候选执行人private String candidate;// 关联的流程变量信息private Map<String, VariableInstance> variableInstances;private Map<String, Object> variables;// 任务发起时间@DateTimeFormat(pattern = "yyyy-MM-dd")@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")private LocalDateTime startTime;//任务创建时间@DateTimeFormat(pattern = "yyyy-MM-dd")@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")private LocalDateTime createTime;//任务完成时间@DateTimeFormat(pattern = "yyyy-MM-dd")@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")private LocalDateTime finishTime;// 审批人当前操作的标识 0:审批 1:拾取 2:审批或者归还private Integer status;}

③ 定义功能接口

package com.ceair.controller;import com.ceair.entity.request.PageReq;
import com.ceair.entity.result.Result;
import com.ceair.entity.vo.TaskListInfoVO;
import com.ceair.service.IMayTaskService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author wangbaohai* @ClassName MyTaskController* @description: 任务信息相关接口* @date 2025年05月01日* @version: 1.0.0*/
@RestController
@RequestMapping("/api/v1/myTask")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "我的任务信息管理", description = "我的任务信息相关接口")
public class MyTaskController {private final IMayTaskService mayTaskService;/*** 分页查询我的待办任务。* <p>* 权限控制:需要拥有 '/api/v1/task/myTodoTask' 权限才能访问。* 接口参数:分页请求对象(pageReq),用于指定分页信息。* 接口用途:在API文档中标识该接口的功能为“分页查询我的待办任务”。* 请求方式:POST 请求,路径为 "/myTodoTask"。** @param pageReq 分页请求对象,包含分页参数(页码、页大小等)。* @return Result<TaskListInfoVO> 返回封装后的分页任务列表信息。*/@PreAuthorize("hasAnyAuthority('/api/v1/myTask/myTodoTask')")@Parameter(name = "pageReq", description = "分页请求对象", required = true)@Operation(summary = "分页查询我的待办任务")@PostMapping("/myTodoTask")public Result<TaskListInfoVO> myTodoTask(@RequestBody PageReq pageReq) {try {// 调用业务层查询我的待办任务TaskListInfoVO taskListInfoVO = mayTaskService.myTodoTask(pageReq);// 返回封装后的分页任务列表信息return Result.success(taskListInfoVO);} catch (Exception e) {log.error("查询我的待办任务失败,原因:{}", e.getMessage());return Result.error("查询我的待办任务失败,原因:" + e.getMessage());}}}

④ 定义服务接口

⑤ 实现服务接口

        这块其实就是本文最核心的代码,其中要使用到Flowable引擎的TaskQuery创建查询工具实现查询功能,另外需要使用Flowable引擎的RepositoryService工具查询流程定义数据补充任务信息,以及需要使用Flowable引擎的HistoryService工具查询流程的发起人信息。

        其中查询当前用户的角色id列表和用户名称都需要用到我们第二步创建的feign接口实现。

package com.ceair.service.impl;import cn.hutool.core.date.DateUtil;
import com.ceair.api.SystemFeignClient;
import com.ceair.entity.model.UserInfo;
import com.ceair.entity.request.PageReq;
import com.ceair.entity.result.Result;
import com.ceair.entity.vo.Oauth2BasicUserVO;
import com.ceair.entity.vo.TaskListInfoVO;
import com.ceair.entity.vo.TaskVO;
import com.ceair.exception.BusinessException;
import com.ceair.service.IMayTaskService;
import com.ceair.util.UserInfoUtils;
import io.micrometer.common.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.stereotype.Service;import java.util.*;
import java.util.stream.Collectors;/*** @author wangbaohai* @ClassName MayTaskServiceImpl* @description: 我的任务信息接口实现* @date 2025年05月01日* @version: 1.0.0*/
@Slf4j
@Service
@RequiredArgsConstructor
public class MayTaskServiceImpl implements IMayTaskService {private final RepositoryService repositoryService;private final SystemFeignClient systemFeignClient;private final TaskService taskService;private final HistoryService historyService;// 用户工具private final UserInfoUtils userInfoUtils;/*** 查询当前用户代办的任务列表** @param pageReq 分页请求对象,包含当前页码和每页大小* @return 返回包含任务列表和总任务数的TaskListInfoVO对象* @throws IllegalArgumentException 如果分页信息为空,则抛出此异常* @throws BusinessException        如果用户未登录或查询角色ID失败,则抛出此异常*/@Overridepublic TaskListInfoVO myTodoTask(PageReq pageReq) {try {// 初始化TaskListInfoVO taskListInfoVO = new TaskListInfoVO();// 分页信息判空if (pageReq == null) {log.error("查询我的待办任务失败,原因:分页信息不能为空");throw new IllegalArgumentException("查询我的待办任务失败,原因:分页信息不能为空");}// 获取分页信息,如果不存在默认查询第一页,每页10条数据long current = (Objects.nonNull(pageReq.getCurrent()) && pageReq.getCurrent() > 0) ? pageReq.getCurrent() :1L;long size = (Objects.nonNull(pageReq.getSize()) && pageReq.getSize() > 0) ? pageReq.getSize() : 10L;// 获取当前用户UserInfo userInfo = userInfoUtils.getUserInfoFromAuthentication();if (userInfo == null) {log.error("查询我的待办任务失败,原因:用户未登录");throw new BusinessException("查询我的待办任务失败,原因:用户未登录");}// 缓存用户ID字符串形式,避免重复调用String userIdStr = userInfo.getId().toString();String account = userInfo.getAccount();// 通过 feign 接口获取当前用的角色ID清单Collection<String> roleIds;Result<List<Long>> roleResult = systemFeignClient.queryRoleIdsByUserId(userInfo.getId());if (roleResult.getCode() != 200 || roleResult.getData() == null) {log.warn("查询我的待办任务失败,原因:{}", roleResult.getMessage());roleIds = Collections.emptyList();} else {roleIds = roleResult.getData().stream().map(String::valueOf).collect(Collectors.toList());}// 设置查询工具(需要查询激活的,办理人/候选人/候选组是我的任务)TaskQuery taskQuery = taskService.createTaskQuery().active().or().taskAssignee(userIdStr).taskCandidateUser(userIdStr);if (!roleIds.isEmpty()) {taskQuery.taskCandidateGroupIn(roleIds);}taskQuery.endOr().orderByTaskCreateTime().desc();// 查询工具设置分页属性并且实行查询动作List<Task> tasks = taskQuery.listPage((int) ((current - 1) * size), (int) (current * size));// 记录待办任务数量long count = taskQuery.count();// 初始化结果数据listList<TaskVO> taskVOS = new ArrayList<>();// 翻译任务数据tasks.stream().filter(Objects::nonNull).forEach(task -> {TaskVO taskVO = new TaskVO();taskVO.setTaskId(task.getId());taskVO.setExecutionId(task.getExecutionId());taskVO.setTaskName(task.getName());taskVO.setProcDefId(task.getProcessDefinitionId());taskVO.setTaskDefKey(task.getTaskDefinitionKey());taskVO.setAssigneeId(task.getAssignee());taskVO.setAssigneeName(StringUtils.isBlank(task.getAssignee()) ? "" : account);// 查询确认 流程定义数据ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();if (processDefinition != null) {taskVO.setProcDefName(processDefinition.getName());taskVO.setProcDefKey(processDefinition.getKey());taskVO.setProcInsId(task.getProcessInstanceId());}// 查询确认 流程发起人HistoricProcessInstance historicProcessInstance =historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();if (historicProcessInstance != null&& StringUtils.isNotBlank(historicProcessInstance.getStartUserId())) {// 确认 流程发起人String startUserId = historicProcessInstance.getStartUserId();taskVO.setStartUserId(startUserId);// 确认流程发起时间taskVO.setStartTime(DateUtil.toLocalDateTime(historicProcessInstance.getStartTime()));// 通过feign接口使用用户ID获取用户信息Result<Oauth2BasicUserVO> userResult =systemFeignClient.queryUserById(Long.valueOf(startUserId));if (userResult.getCode() == 200 && userResult.getData() != null) {taskVO.setStartUserName(userResult.getData().getName());}}// 确认任务对于当前办理人是需要办理还是拾取还是归还taskVO.setStatus(judgeStatus(task.getProcessDefinitionId(), task.getTaskDefinitionKey(),task.getAssignee()));// 集成封装taskVOS.add(taskVO);});// 返回结果taskListInfoVO.setTaskCount(count);taskListInfoVO.setTaskList(taskVOS);return taskListInfoVO;} catch (IllegalArgumentException e) {log.error("查询我的待办任务失败,原因:参数错误", e);throw new BusinessException("查询我的待办任务失败,原因:参数错误", e);} catch (BusinessException e) {log.error("查询我的待办任务失败,原因:业务异常", e);throw new BusinessException("查询我的待办任务失败,原因:业务异常", e);} catch (Exception e) {log.error("查询我的待办任务失败,原因:未知异常", e);throw new BusinessException("查询我的待办任务失败,原因:未知异常", e);}}/*** 根据流程定义ID、任务定义键和指定的办理人判断任务状态** @param processDefinitionId 流程定义ID,用于识别特定的业务流程* @param taskDefinitionKey   任务定义键,用于在流程中定位特定的任务* @param assignee            指定的办理人,用于判断任务的当前状态* @return 返回任务的状态代码:0-审批,1-拾取,2-审批或归还;如果无法判断状态,则返回null*/private Integer judgeStatus(String processDefinitionId, String taskDefinitionKey, String assignee) {// 参数校验if (StringUtils.isBlank(processDefinitionId) || StringUtils.isBlank(taskDefinitionKey)) {return null;}try {// 获取 BpmnModel 对象BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);Process mainProcess = bpmnModel != null ? bpmnModel.getMainProcess() : null;if (mainProcess == null) {return null;}Collection<FlowElement> flowElements = mainProcess.getFlowElements();// 查找目标用户任务return flowElements.stream().filter(Objects::nonNull).filter(flowElement -> flowElement instanceof UserTask).map(flowElement -> (UserTask) flowElement).filter(userTask -> taskDefinitionKey.equals(userTask.getId())).findFirst().map(userTask -> {if (!StringUtils.isBlank(userTask.getAssignee())) {// 流程节点指定办理人:审批状态return 0; // 审批} else {if (StringUtils.isBlank(assignee)) {// 未指定实际办理人:拾取状态return 1; // 拾取} else {// 已有实际办理人:审批/归还状态return 2; // 审批或归还}}}).orElse(null);} catch (Exception e) {log.error("判断流程状态失败,具体原因为: {}", e.getMessage(), e);return null;}}}

四、我的待办界面

① 定义前端实体

// 任务实体 VO
export interface TaskVO {taskId: string // 任务编号 (Java String)executionId: string // 任务执行编号taskName: string // 任务名称taskDefKey: string // 任务 KeyassigneeId: string // 任务执行人 IdassigneeName: string // 任务执行人名称startUserId: string // 流程发起人 IdstartUserName: string // 流程发起人名称category: string // 流程类型procVars: any // 流程变量信息 (Java Object)taskLocalVars: any // 局部变量信息deployId: string // 流程部署编号procDefId: string // 流程定义 IDprocDefKey: string // 流程 KeyprocDefName: string // 流程定义名称procDefVersion: number // 流程定义版本号 (Java int)procInsId: string // 流程实例 IDhisProcInsId: string // 历史流程实例 IDduration: string // 任务耗时 (Java String)candidate: string // 候选执行人variableInstances: Record<string, any> // 关联的流程变量信息 (Java Map<String,VariableInstance>)variables: Record<string, any> // 关联的流程变量 (Java Map<String,Object>)startTime: string // 任务发起时间 (Java LocalDateTime → string)createTime: string // 任务创建时间finishTime: string // 任务完成时间status: number // 审批人当前操作的标识 (Java Integer)
}// 任务列表信息 VO
export interface TaskListInfoVO {taskList: TaskVO[] // 任务清单 (Java List<TaskVO>)taskCount: number // 任务总数 (Java Long → number)
}export interface PageReq {current: number // 当前页码,后端默认 1size: number // 每页记录数,后端默认 10
}

② 封装前端接口

import type { PageReq } from './taskType'
import request from '@/utils/http/request'/*** 分页查询我的待办任务*/
export function getMyTaskPage(data: PageReq) {return request.post<any>({url: '/pm-process/api/v1/myTask/myTodoTask',data,})
}

③ 绘制页面

        界面里包含了一个列表,列表里的操作列有3个按钮,但是会根据数据的状态动态调整是否展示。

<script lang="ts" setup>
import type { TaskVO } from '@/api/task/taskType'
import { getMyTaskPage } from '@/api/task/taskApi'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'// 定义当前页码
const currentPage = ref<number>(1)
// 默认页行数
const pageSize = ref<number>(10)
// 数据总数
const total = ref<number>(0)
// 定义响应式数据 myTaskList,用于存储我的任务列表数据
const myTaskList = ref<TaskVO[]>([])
// 表格列定义
const tableColumns = [{ label: '#', type: 'index', align: 'center', width: '50px' },{ label: '任务编号', prop: 'taskId', align: 'center' },{ label: '任务名称', prop: 'taskName', align: 'center' },{ label: '任务执行人名称', prop: 'assigneeName', align: 'center' },{ label: '流程发起人名称', prop: 'startUserName', align: 'center' },{ label: '任务发起时间', prop: 'startTime', align: 'center' },{ label: '流程定义名称', prop: 'procDefName', align: 'center' },{ label: '流程实例ID', prop: 'procInsId', align: 'center' },{ label: '操作', align: 'center', width: '200px' },
]onMounted(() => {// 初始化分页参数并加载第一页任务数据currentPage.value = 1 // 设置当前页为第一页pageSize.value = 10 // 每页展示10条任务记录getMyTaskPageData() // 调用获取我的任务分页数据的方法
})/*** 异步函数:获取我的任务列表数据* 该函数通过调用后端接口,获取当前用户的任务列表,并根据分页参数进行数据更新*/
async function getMyTaskPageData() {try {// 设置分页参数const pageReq = {current: currentPage.value,size: pageSize.value,}// 调用接口获取我的任务列表数据const result: any = await getMyTaskPage(pageReq)// 如果接口调用成功且返回的状态码为200,则更新数据if (result.success && result.code === 200) {// 更新数据myTaskList.value = result.data.taskList// 收集数据总数total.value = result.data.taskCount}else {// 如果接口调用失败,显示错误提示信息ElMessage({message: '查询失败',type: 'error',})}}catch (error) {// 捕获异常并提取错误信息let errorMessage = '未知错误'if (error instanceof Error) {errorMessage = error.message}// 显示操作失败的错误提示信息ElMessage({message: `查询失败: ${errorMessage || '未知错误'}`,type: 'error',})}
}/*** 处理页面数据函数* 本函数用于重新获取当前页面所需的数据* 它通过调用 getMyTaskPageData 函数来实现数据的重新加载*/
function handerPageData() {// 重新加载数据getMyTaskPageData()
}
</script><template><el-table style="margin: 10px 0px;" :border="true" :data="myTaskList"><!-- ID 区域 --><el-table-column type="selection" align="center" width="50px" /><!-- 表格数据 区域 --><el-table-columnv-for="(column, index) in tableColumns":key="index":type="column.type":label="column.label":prop="column.prop":align="column.align":width="column.width"><!-- 使用单个 template 包裹所有条件 --><template #default="scope"><!-- 判断是否是操作列 --><div v-if="column.label === '操作'"><el-button v-if="scope.row.status === 0 || scope.row.status === 2" type="primary">审批</el-button><el-button v-if="scope.row.status === 1" type="primary">拾取</el-button><el-button v-if="scope.row.status === 2" type="primary">归还</el-button></div></template></el-table-column></el-table><!-- 分页器 --><el-paginationv-model:current-page="currentPage"v-model:page-size="pageSize":page-sizes="[10, 20, 30, 40, 50]"layout="prev, pager, next, jumper,->, sizes, total":total="Math.max(total, 0)"@current-change="getMyTaskPageData"@size-change="handerPageData"/>
</template><style scoped></style>

五、增加菜单以及按钮权限

六、功能验证

① 指定办理人的场景

        这种场景我们应该点亮办理按钮

        验证下来是ok的,能看到任务并且任务是直接审批的。

② 指定候选人的场景

        这种场景我们应该只能点亮拾取按钮

        验证下来是ok的,能看到任务并且任务是可拾取的。

③ 指定候选组的场景

        admin的角色是超级管理员

        验证下来是ok的,能看到任务并且任务是可拾取的。

七、后记

        任务的归还点亮需要完整拾取功能,这个我在下一个文章中再来实现吧,本文的完整代码仓库地址请查看专栏第一篇文章的说明。

本文的后端分支是 process-9

本文的前端分支是 process-11

相关文章:

  • Ethan独立开发产品日报 | 2025-04-30
  • WPF之Image控件详解
  • 文件包含漏洞学习
  • Redis 挂掉后高并发系统的应对策略:使用 Sentinel 实现限流降级与 SkyWalking 监控优化
  • 什么是:云边端一体化架构
  • Matlab/Simulink - BLDC直流无刷电机仿真基础教程(五) - animateRotorPosition脚本讲解与使用
  • Unity 几种主流的热更新方式
  • 【Java学习笔记】递归
  • 【白雪讲堂 】GEO兴起:AI搜索时代的内容优化新战场
  • 哈希表笔记(三)Java Hashmap
  • 用手机相册教我数组概念——照片分类术[特殊字符][特殊字符]
  • AXI中的out of order和interleaving的定义和两者的差别?
  • mysql-窗口函数一
  • 缓存:缓解读库压力的高效方案与应用实践
  • Transformer架构的解耦重组现象
  • JVM——Java 虚拟机是如何加载 Java 类的?
  • RAG工程-基于LangChain 实现 Advanced RAG(预检索-查询优化)(下)
  • 记录搭建自己的应用中心-需求看板搭建
  • 如何解决 H5 远程收款的问题呢?
  • 计算机网络——HTTP/IP 协议通俗入门详解
  • “非思”的思想——探索失语者的思想史
  • 澎湃回声丨23岁小伙“被精神病”8年续:今日将被移出“重精”管理系统
  • 美航母撞船后又遇战机坠海,专家:长时间作战部署疲于奔命是主因
  • 圆桌|如何应对特朗普政府的关税霸凌?一种联合国视角的思考
  • 江西德安回应“义门陈遗址建筑被没收”:将交由规范的义门陈相关社会组织管理
  • “上海-日喀则”直飞航线正式通航,将于5月1日开启首航