fys
This commit is contained in:
@ -0,0 +1,29 @@
|
||||
package com.fuyuanshen.workflow.common;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义条件注解,用于基于配置启用或禁用特定功能
|
||||
* <p>
|
||||
* 该注解只会在配置文件中 `warm-flow.enabled=true` 时,标注了此注解的类或方法才会被 Spring 容器加载
|
||||
* <p>
|
||||
* 示例配置:
|
||||
* <pre>
|
||||
* warm-flow:
|
||||
* enabled: true # 设置为 true 时,启用工作流功能
|
||||
* </pre>
|
||||
* <p>
|
||||
* 使用此注解时,可以动态控制工作流功能是否启用,而不需要修改代码逻辑
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@ConditionalOnProperty(value = "warm-flow.enabled", havingValue = "true")
|
||||
public @interface ConditionalOnEnable {
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package com.fuyuanshen.workflow.common.constant;
|
||||
|
||||
|
||||
/**
|
||||
* 工作流常量
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
public interface FlowConstant {
|
||||
|
||||
/**
|
||||
* 流程发起人
|
||||
*/
|
||||
String INITIATOR = "initiator";
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
*/
|
||||
String BUSINESS_ID = "businessId";
|
||||
|
||||
/**
|
||||
* 委托
|
||||
*/
|
||||
String DELEGATE_TASK = "delegateTask";
|
||||
|
||||
/**
|
||||
* 转办
|
||||
*/
|
||||
String TRANSFER_TASK = "transferTask";
|
||||
|
||||
/**
|
||||
* 加签
|
||||
*/
|
||||
String ADD_SIGNATURE = "addSignature";
|
||||
|
||||
/**
|
||||
* 减签
|
||||
*/
|
||||
String REDUCTION_SIGNATURE = "reductionSignature";
|
||||
|
||||
/**
|
||||
* 流程分类Id转名称
|
||||
*/
|
||||
String CATEGORY_ID_TO_NAME = "category_id_to_name";
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
String FLOW_CATEGORY_NAME = "flow_category_name#30d";
|
||||
|
||||
/**
|
||||
* 默认租户OA申请分类id
|
||||
*/
|
||||
Long FLOW_CATEGORY_ID = 100L;
|
||||
|
||||
/**
|
||||
* 是否为申请人提交常量
|
||||
*/
|
||||
String SUBMIT = "submit";
|
||||
|
||||
/**
|
||||
* 抄送常量
|
||||
*/
|
||||
String FLOW_COPY_LIST = "flowCopyList";
|
||||
|
||||
/**
|
||||
* 消息类型常量
|
||||
*/
|
||||
String MESSAGE_TYPE = "messageType";
|
||||
|
||||
/**
|
||||
* 消息通知常量
|
||||
*/
|
||||
String MESSAGE_NOTICE = "messageNotice";
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.fuyuanshen.workflow.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 按钮权限枚举
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ButtonPermissionEnum implements NodeExtEnum {
|
||||
|
||||
/**
|
||||
* 是否弹窗选人
|
||||
*/
|
||||
POP("是否弹窗选人", "pop", false),
|
||||
|
||||
/**
|
||||
* 是否能委托
|
||||
*/
|
||||
TRUST("是否能委托", "trust", false),
|
||||
|
||||
/**
|
||||
* 是否能转办
|
||||
*/
|
||||
TRANSFER("是否能转办", "transfer", false),
|
||||
|
||||
/**
|
||||
* 是否能抄送
|
||||
*/
|
||||
COPY("是否能抄送", "copy", false),
|
||||
|
||||
/**
|
||||
* 是否显示退回
|
||||
*/
|
||||
BACK("是否显示退回", "back", true),
|
||||
|
||||
/**
|
||||
* 是否能加签
|
||||
*/
|
||||
ADD_SIGN("是否能加签", "addSign", false),
|
||||
|
||||
/**
|
||||
* 是否能减签
|
||||
*/
|
||||
SUB_SIGN("是否能减签", "subSign", false),
|
||||
|
||||
/**
|
||||
* 是否能终止
|
||||
*/
|
||||
TERMINATION("是否能终止", "termination", true),
|
||||
|
||||
/**
|
||||
* 是否能上传附件
|
||||
*/
|
||||
FILE("是否能上传附件", "file", true);
|
||||
|
||||
private final String label;
|
||||
private final String value;
|
||||
private final boolean selected;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
package com.fuyuanshen.workflow.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 消息类型枚举
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum MessageTypeEnum {
|
||||
|
||||
/**
|
||||
* 站内信
|
||||
*/
|
||||
SYSTEM_MESSAGE("1", "站内信"),
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
EMAIL_MESSAGE("2", "邮箱"),
|
||||
|
||||
/**
|
||||
* 短信
|
||||
*/
|
||||
SMS_MESSAGE("3", "短信");
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String desc;
|
||||
|
||||
private static final Map<String, MessageTypeEnum> MESSAGE_TYPE_ENUM_MAP = Arrays.stream(values())
|
||||
.collect(Collectors.toConcurrentMap(MessageTypeEnum::getCode, Function.identity()));
|
||||
|
||||
/**
|
||||
* 根据消息类型 code 获取 MessageTypeEnum
|
||||
*
|
||||
* @param code 消息类型code
|
||||
* @return MessageTypeEnum
|
||||
*/
|
||||
public static MessageTypeEnum getByCode(String code) {
|
||||
return MESSAGE_TYPE_ENUM_MAP.getOrDefault(code, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package com.fuyuanshen.workflow.common.enums;
|
||||
|
||||
/**
|
||||
* 节点扩展属性枚举
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
public interface NodeExtEnum {
|
||||
|
||||
/**
|
||||
* 选项label
|
||||
*
|
||||
* @return 选项label
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* 选项值
|
||||
*
|
||||
* @return 选项值
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
/**
|
||||
* 是否默认选中
|
||||
*
|
||||
* @return 是否默认选中
|
||||
*/
|
||||
boolean isSelected();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,109 @@
|
||||
package com.fuyuanshen.workflow.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 任务分配人枚举
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TaskAssigneeEnum {
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*/
|
||||
USER("用户", ""),
|
||||
|
||||
/**
|
||||
* 角色
|
||||
*/
|
||||
ROLE("角色", "role:"),
|
||||
|
||||
/**
|
||||
* 部门
|
||||
*/
|
||||
DEPT("部门", "dept:"),
|
||||
|
||||
/**
|
||||
* 岗位
|
||||
*/
|
||||
POST("岗位", "post:");
|
||||
|
||||
private final String desc;
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* 根据描述获取对应的枚举类型
|
||||
* <p>
|
||||
* 通过传入描述,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。
|
||||
* </p>
|
||||
*
|
||||
* @param desc 描述,用于匹配对应的枚举项
|
||||
* @return TaskAssigneeEnum 返回对应的枚举类型
|
||||
* @throws ServiceException 如果未找到匹配的枚举项
|
||||
*/
|
||||
public static TaskAssigneeEnum fromDesc(String desc) {
|
||||
for (TaskAssigneeEnum type : values()) {
|
||||
if (type.getDesc().equals(desc)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new ServiceException("未知的办理人类型: " + desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码获取对应的枚举类型
|
||||
* <p>
|
||||
* 通过传入代码,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。
|
||||
* </p>
|
||||
*
|
||||
* @param code 代码,用于匹配对应的枚举项
|
||||
* @return TaskAssigneeEnum 返回对应的枚举类型
|
||||
* @throws IllegalArgumentException 如果未找到匹配的枚举项
|
||||
*/
|
||||
public static TaskAssigneeEnum fromCode(String code) {
|
||||
for (TaskAssigneeEnum type : values()) {
|
||||
if (type.getCode().equals(code)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new ServiceException("未知的办理人类型代码: " + code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有办理人类型的描述列表
|
||||
* <p>
|
||||
* 获取当前枚举类所有项的描述字段列表,通常用于展示选择项。
|
||||
* </p>
|
||||
*
|
||||
* @return List<String> 返回所有办理人类型的描述列表
|
||||
*/
|
||||
public static List<String> getAssigneeTypeList() {
|
||||
return Arrays.stream(values())
|
||||
.map(TaskAssigneeEnum::getDesc)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有办理人类型的代码列表
|
||||
* <p>
|
||||
* 获取当前枚举类所有项的代码字段列表,通常用于程序内部逻辑的判断。
|
||||
* </p>
|
||||
*
|
||||
* @return List<String> 返回所有办理人类型的代码列表
|
||||
*/
|
||||
public static List<String> getAssigneeCodeList() {
|
||||
return Arrays.stream(values())
|
||||
.map(TaskAssigneeEnum::getCode)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
package com.fuyuanshen.workflow.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 人员类型
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TaskAssigneeType {
|
||||
|
||||
/**
|
||||
* 待办任务的审批人权限
|
||||
* <p>该权限表示用户是待办任务的审批人,负责审核任务的执行情况。</p>
|
||||
*/
|
||||
APPROVER("1", "待办任务的审批人权限"),
|
||||
|
||||
/**
|
||||
* 待办任务的转办人权限
|
||||
* <p>该权限表示用户是待办任务的转办人,负责将任务分配给其他人员。</p>
|
||||
*/
|
||||
TRANSFER("2", "待办任务的转办人权限"),
|
||||
|
||||
/**
|
||||
* 待办任务的委托人权限
|
||||
* <p>该权限表示用户是待办任务的委托人,能够委托其他人代为处理任务。</p>
|
||||
*/
|
||||
DELEGATE("3", "待办任务的委托人权限"),
|
||||
|
||||
/**
|
||||
* 待办任务的抄送人权限
|
||||
* <p>该权限表示用户是待办任务的抄送人,仅接收任务信息的通知,不参与任务的审批或处理。</p>
|
||||
*/
|
||||
COPY("4", "待办任务的抄送人权限");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package com.fuyuanshen.workflow.common.enums;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 任务状态枚举
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TaskStatusEnum {
|
||||
|
||||
/**
|
||||
* 撤销
|
||||
*/
|
||||
CANCEL("cancel", "撤销"),
|
||||
|
||||
/**
|
||||
* 通过
|
||||
*/
|
||||
PASS("pass", "通过"),
|
||||
|
||||
/**
|
||||
* 待审核
|
||||
*/
|
||||
WAITING("waiting", "待审核"),
|
||||
|
||||
/**
|
||||
* 作废
|
||||
*/
|
||||
INVALID("invalid", "作废"),
|
||||
|
||||
/**
|
||||
* 退回
|
||||
*/
|
||||
BACK("back", "退回"),
|
||||
|
||||
/**
|
||||
* 终止
|
||||
*/
|
||||
TERMINATION("termination", "终止"),
|
||||
|
||||
/**
|
||||
* 转办
|
||||
*/
|
||||
TRANSFER("transfer", "转办"),
|
||||
|
||||
/**
|
||||
* 委托
|
||||
*/
|
||||
DEPUTE("depute", "委托"),
|
||||
|
||||
/**
|
||||
* 抄送
|
||||
*/
|
||||
COPY("copy", "抄送"),
|
||||
|
||||
/**
|
||||
* 加签
|
||||
*/
|
||||
SIGN("sign", "加签"),
|
||||
|
||||
/**
|
||||
* 减签
|
||||
*/
|
||||
SIGN_OFF("sign_off", "减签"),
|
||||
|
||||
/**
|
||||
* 超时
|
||||
*/
|
||||
TIMEOUT("timeout", "超时");
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private final String status;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
private static final Map<String, String> STATUS_DESC_MAP = Arrays.stream(values())
|
||||
.collect(Collectors.toConcurrentMap(TaskStatusEnum::getStatus, TaskStatusEnum::getDesc));
|
||||
|
||||
/**
|
||||
* 任务业务状态
|
||||
*
|
||||
* @param status 状态
|
||||
*/
|
||||
public static String findByStatus(String status) {
|
||||
// 从缓存中直接获取描述
|
||||
return STATUS_DESC_MAP.getOrDefault(status, StrUtil.EMPTY);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.fuyuanshen.workflow.config;
|
||||
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* warmFlow配置
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Configuration
|
||||
public class WarmFlowConfig {
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,136 @@
|
||||
package com.fuyuanshen.workflow.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowCategoryBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowCategoryVo;
|
||||
import com.fuyuanshen.workflow.service.IFlwCategoryService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程分类
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/category")
|
||||
public class FlwCategoryController extends BaseController {
|
||||
|
||||
private final IFlwCategoryService flwCategoryService;
|
||||
|
||||
/**
|
||||
* 查询流程分类列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:list")
|
||||
@GetMapping("/list")
|
||||
public R<List<FlowCategoryVo>> list(FlowCategoryBo bo) {
|
||||
List<FlowCategoryVo> list = flwCategoryService.queryList(bo);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出流程分类列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:export")
|
||||
@Log(title = "流程分类", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(FlowCategoryBo bo, HttpServletResponse response) {
|
||||
List<FlowCategoryVo> list = flwCategoryService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "流程分类", FlowCategoryVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程分类详细信息
|
||||
*
|
||||
* @param categoryId 主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:query")
|
||||
@GetMapping("/{categoryId}")
|
||||
public R<FlowCategoryVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long categoryId) {
|
||||
flwCategoryService.checkCategoryDataScope(categoryId);
|
||||
return R.ok(flwCategoryService.queryById(categoryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程分类
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:add")
|
||||
@Log(title = "流程分类", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody FlowCategoryBo category) {
|
||||
if (!flwCategoryService.checkCategoryNameUnique(category)) {
|
||||
return R.fail("新增流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在");
|
||||
}
|
||||
return toAjax(flwCategoryService.insertByBo(category));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改流程分类
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:edit")
|
||||
@Log(title = "流程分类", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) {
|
||||
Long categoryId = category.getCategoryId();
|
||||
flwCategoryService.checkCategoryDataScope(categoryId);
|
||||
if (!flwCategoryService.checkCategoryNameUnique(category)) {
|
||||
return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在");
|
||||
} else if (category.getParentId().equals(categoryId)) {
|
||||
return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,上级流程分类不能是自己");
|
||||
}
|
||||
return toAjax(flwCategoryService.updateByBo(category));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程分类
|
||||
*
|
||||
* @param categoryId 主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:remove")
|
||||
@Log(title = "流程分类", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{categoryId}")
|
||||
public R<Void> remove(@PathVariable Long categoryId) {
|
||||
if (FlowConstant.FLOW_CATEGORY_ID.equals(categoryId)) {
|
||||
return R.warn("默认流程分类,不允许删除");
|
||||
}
|
||||
if (flwCategoryService.hasChildByCategoryId(categoryId)) {
|
||||
return R.warn("存在下级流程分类,不允许删除");
|
||||
}
|
||||
if (flwCategoryService.checkCategoryExistDefinition(categoryId)) {
|
||||
return R.warn("流程分类存在流程定义,不允许删除");
|
||||
}
|
||||
return toAjax(flwCategoryService.deleteWithValidById(categoryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程分类树列表
|
||||
*
|
||||
* @param categoryBo 流程分类
|
||||
*/
|
||||
@GetMapping("/categoryTree")
|
||||
public R<List<Tree<String>>> categoryTree(FlowCategoryBo categoryBo) {
|
||||
return R.ok(flwCategoryService.selectCategoryTreeList(categoryBo));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
package com.fuyuanshen.workflow.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowDefinitionVo;
|
||||
import com.fuyuanshen.workflow.service.IFlwDefinitionService;
|
||||
import org.dromara.warm.flow.core.entity.Definition;
|
||||
import org.dromara.warm.flow.core.service.DefService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程定义管理 控制层
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/definition")
|
||||
public class FlwDefinitionController extends BaseController {
|
||||
|
||||
private final DefService defService;
|
||||
private final IFlwDefinitionService flwDefinitionService;
|
||||
|
||||
/**
|
||||
* 查询流程定义列表
|
||||
*
|
||||
* @param flowDefinition 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<FlowDefinitionVo> list(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||
return flwDefinitionService.queryList(flowDefinition, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未发布的流程定义列表
|
||||
*
|
||||
* @param flowDefinition 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/unPublishList")
|
||||
public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||
return flwDefinitionService.unPublishList(flowDefinition, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程定义详细信息
|
||||
*
|
||||
* @param id 流程定义id
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public R<Definition> getInfo(@PathVariable Long id) {
|
||||
return R.ok(defService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程定义
|
||||
*
|
||||
* @param flowDefinition 参数
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
@RepeatSubmit()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Boolean> add(@RequestBody FlowDefinition flowDefinition) {
|
||||
return R.ok(defService.checkAndSave(flowDefinition));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改流程定义
|
||||
*
|
||||
* @param flowDefinition 参数
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
@RepeatSubmit()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Boolean> edit(@RequestBody FlowDefinition flowDefinition) {
|
||||
return R.ok(defService.updateById(flowDefinition));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.INSERT)
|
||||
@PutMapping("/publish/{id}")
|
||||
@RepeatSubmit()
|
||||
public R<Boolean> publish(@PathVariable Long id) {
|
||||
return R.ok(flwDefinitionService.publish(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消发布流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.INSERT)
|
||||
@PutMapping("/unPublish/{id}")
|
||||
@RepeatSubmit()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Boolean> unPublish(@PathVariable Long id) {
|
||||
return R.ok(defService.unPublish(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程定义
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@PathVariable List<Long> ids) {
|
||||
return toAjax(flwDefinitionService.removeDef(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/copy/{id}")
|
||||
@RepeatSubmit()
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Boolean> copy(@PathVariable Long id) {
|
||||
return R.ok(defService.copyDef(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入流程定义
|
||||
*
|
||||
* @param file 文件
|
||||
* @param category 分类
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importDef")
|
||||
public R<Boolean> importDef(MultipartFile file, String category) {
|
||||
return R.ok(flwDefinitionService.importJson(file, category));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
* @param response 响应
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
@Log(title = "流程定义", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/exportDef/{id}")
|
||||
public void exportDef(@PathVariable Long id, HttpServletResponse response) throws IOException {
|
||||
flwDefinitionService.exportDef(id, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程定义JSON字符串
|
||||
*
|
||||
* @param id 流程定义id
|
||||
*/
|
||||
@GetMapping("/xmlString/{id}")
|
||||
public R<String> xmlString(@PathVariable Long id) {
|
||||
return R.ok("操作成功", defService.exportJson(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活/挂起流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
* @param active 激活/挂起
|
||||
*/
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/active/{id}")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Boolean> active(@PathVariable Long id, @RequestParam boolean active) {
|
||||
return R.ok(active ? defService.active(id) : defService.unActive(id));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
package com.fuyuanshen.workflow.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowCancelBo;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowInstanceBo;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowInvalidBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowInstanceVo;
|
||||
import com.fuyuanshen.workflow.service.IFlwInstanceService;
|
||||
import org.dromara.warm.flow.core.service.InsService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程实例管理 控制层
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/instance")
|
||||
public class FlwInstanceController extends BaseController {
|
||||
|
||||
private final InsService insService;
|
||||
private final IFlwInstanceService flwInstanceService;
|
||||
|
||||
/**
|
||||
* 查询正在运行的流程实例列表
|
||||
*
|
||||
* @param flowInstanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/pageByRunning")
|
||||
public TableDataInfo<FlowInstanceVo> selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
|
||||
return flwInstanceService.selectRunningInstanceList(flowInstanceBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已结束的流程实例列表
|
||||
*
|
||||
* @param flowInstanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/pageByFinish")
|
||||
public TableDataInfo<FlowInstanceVo> selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
|
||||
return flwInstanceService.selectFinishInstanceList(flowInstanceBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据业务id查询流程实例详细信息
|
||||
*
|
||||
* @param businessId 业务id
|
||||
*/
|
||||
@GetMapping("/getInfo/{businessId}")
|
||||
public R<FlowInstanceVo> getInfo(@PathVariable Long businessId) {
|
||||
return R.ok(flwInstanceService.queryByBusinessId(businessId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照业务id删除流程实例
|
||||
*
|
||||
* @param businessIds 业务id
|
||||
*/
|
||||
@DeleteMapping("/deleteByBusinessIds/{businessIds}")
|
||||
public R<Void> deleteByBusinessIds(@PathVariable List<Long> businessIds) {
|
||||
return toAjax(flwInstanceService.deleteByBusinessIds(businessIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照实例id删除流程实例
|
||||
*
|
||||
* @param instanceIds 实例id
|
||||
*/
|
||||
@DeleteMapping("/deleteByInstanceIds/{instanceIds}")
|
||||
public R<Void> deleteByInstanceIds(@PathVariable List<Long> instanceIds) {
|
||||
return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销流程
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/cancelProcessApply")
|
||||
public R<Void> cancelProcessApply(@RequestBody FlowCancelBo bo) {
|
||||
return toAjax(flwInstanceService.cancelProcessApply(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活/挂起流程实例
|
||||
*
|
||||
* @param id 流程实例id
|
||||
* @param active 激活/挂起
|
||||
*/
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/active/{id}")
|
||||
public R<Boolean> active(@PathVariable Long id, @RequestParam boolean active) {
|
||||
return R.ok(active ? insService.active(id) : insService.unActive(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登陆人发起的流程实例
|
||||
*
|
||||
* @param flowInstanceBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/pageByCurrent")
|
||||
public TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
|
||||
return flwInstanceService.selectCurrentInstanceList(flowInstanceBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程图,流程记录
|
||||
*
|
||||
* @param businessId 业务id
|
||||
*/
|
||||
@GetMapping("/flowHisTaskList/{businessId}")
|
||||
public R<Map<String, Object>> flowHisTaskList(@PathVariable String businessId) {
|
||||
return R.ok(flwInstanceService.flowHisTaskList(businessId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程变量
|
||||
*
|
||||
* @param instanceId 流程实例id
|
||||
*/
|
||||
@GetMapping("/instanceVariable/{instanceId}")
|
||||
public R<Map<String, Object>> instanceVariable(@PathVariable Long instanceId) {
|
||||
return R.ok(flwInstanceService.instanceVariable(instanceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 作废流程
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Log(title = "流程实例管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/invalid")
|
||||
public R<Boolean> invalid(@Validated @RequestBody FlowInvalidBo bo) {
|
||||
return R.ok(flwInstanceService.processInvalid(bo));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
package com.fuyuanshen.workflow.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.domain.dto.StartProcessReturnDTO;
|
||||
import com.fuyuanshen.common.core.domain.dto.UserDTO;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import org.dromara.warm.flow.core.entity.Node;
|
||||
import org.dromara.warm.flow.orm.entity.FlowNode;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.domain.bo.*;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowHisTaskVo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowTaskVo;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务管理 控制层
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/task")
|
||||
public class FlwTaskController extends BaseController {
|
||||
|
||||
private final IFlwTaskService flwTaskService;
|
||||
|
||||
/**
|
||||
* 启动任务
|
||||
*
|
||||
* @param startProcessBo 启动流程参数
|
||||
*/
|
||||
@Log(title = "任务管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/startWorkFlow")
|
||||
public R<StartProcessReturnDTO> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) {
|
||||
StartProcessReturnDTO startProcessReturn = flwTaskService.startWorkFlow(startProcessBo);
|
||||
return R.ok("提交成功", startProcessReturn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 办理任务
|
||||
*
|
||||
* @param completeTaskBo 办理任务参数
|
||||
*/
|
||||
@Log(title = "任务管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/completeTask")
|
||||
public R<Void> completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) {
|
||||
return toAjax(flwTaskService.completeTask(completeTaskBo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的待办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/pageByTaskWait")
|
||||
public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
return flwTaskService.pageByTaskWait(flowTaskBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的已办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
|
||||
@GetMapping("/pageByTaskFinish")
|
||||
public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
return flwTaskService.pageByTaskFinish(flowTaskBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询待办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/pageByAllTaskWait")
|
||||
public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
return flwTaskService.pageByAllTaskWait(flowTaskBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/pageByAllTaskFinish")
|
||||
public TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
return flwTaskService.pageByAllTaskFinish(flowTaskBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的抄送
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@GetMapping("/pageByTaskCopy")
|
||||
public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
return flwTaskService.pageByTaskCopy(flowTaskBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据taskId查询代表任务
|
||||
*
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
@GetMapping("/getTask/{taskId}")
|
||||
public R<FlowTaskVo> getTask(@PathVariable Long taskId) {
|
||||
return R.ok(flwTaskService.selectById(taskId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一节点信息
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@PostMapping("/getNextNodeList")
|
||||
public R<List<FlowNode>> getNextNodeList(@RequestBody FlowNextNodeBo bo) {
|
||||
return R.ok(flwTaskService.getNextNodeList(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 终止任务
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Log(title = "任务管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/terminationTask")
|
||||
public R<Boolean> terminationTask(@RequestBody FlowTerminationBo bo) {
|
||||
return R.ok(flwTaskService.terminationTask(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务操作
|
||||
*
|
||||
* @param bo 参数
|
||||
* @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
|
||||
*/
|
||||
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PostMapping("/taskOperation/{taskOperation}")
|
||||
public R<Void> taskOperation(@Validated @RequestBody TaskOperationBo bo, @PathVariable String taskOperation) {
|
||||
return toAjax(flwTaskService.taskOperation(bo, taskOperation));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改任务办理人
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @param userId 办理人id
|
||||
*/
|
||||
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/updateAssignee/{userId}")
|
||||
public R<Void> updateAssignee(@RequestBody List<Long> taskIdList, @PathVariable String userId) {
|
||||
return toAjax(flwTaskService.updateAssignee(taskIdList, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回审批
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Log(title = "任务管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/backProcess")
|
||||
public R<Void> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo bo) {
|
||||
return toAjax(flwTaskService.backProcess(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可驳回的前置节点
|
||||
*
|
||||
* @param definitionId 流程定义id
|
||||
* @param nowNodeCode 当前节点
|
||||
*/
|
||||
@GetMapping("/getBackTaskNode/{definitionId}/{nowNodeCode}")
|
||||
public R<List<Node>> getBackTaskNode(@PathVariable Long definitionId, @PathVariable String nowNodeCode) {
|
||||
return R.ok(flwTaskService.getBackTaskNode(definitionId, nowNodeCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前任务的所有办理人
|
||||
*
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
@GetMapping("/currentTaskAllUser/{taskId}")
|
||||
public R<List<UserDTO>> currentTaskAllUser(@PathVariable Long taskId) {
|
||||
return R.ok(flwTaskService.currentTaskAllUser(taskId));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package com.fuyuanshen.workflow.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.domain.bo.TestLeaveBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.TestLeaveVo;
|
||||
import com.fuyuanshen.workflow.service.ITestLeaveService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 请假
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-07-21
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/leave")
|
||||
public class TestLeaveController extends BaseController {
|
||||
|
||||
private final ITestLeaveService testLeaveService;
|
||||
|
||||
/**
|
||||
* 查询请假列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:leave:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<TestLeaveVo> list(TestLeaveBo bo, PageQuery pageQuery) {
|
||||
return testLeaveService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出请假列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:leave:export")
|
||||
@Log(title = "请假", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(TestLeaveBo bo, HttpServletResponse response) {
|
||||
List<TestLeaveVo> list = testLeaveService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "请假", TestLeaveVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请假详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:leave:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<TestLeaveVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(testLeaveService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增请假
|
||||
*/
|
||||
@SaCheckPermission("workflow:leave:add")
|
||||
@Log(title = "请假", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<TestLeaveVo> add(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) {
|
||||
return R.ok(testLeaveService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改请假
|
||||
*/
|
||||
@SaCheckPermission("workflow:leave:edit")
|
||||
@Log(title = "请假", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<TestLeaveVo> edit(@Validated(EditGroup.class) @RequestBody TestLeaveBo bo) {
|
||||
return R.ok(testLeaveService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除请假
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("workflow:leave:remove")
|
||||
@Log(title = "请假", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids)));
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package com.fuyuanshen.workflow.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程分类对象 wf_category
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-06-27
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("flow_category")
|
||||
public class FlowCategory extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程分类ID
|
||||
*/
|
||||
@TableId(value = "category_id")
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 父流程分类id
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 祖级列表
|
||||
*/
|
||||
private String ancestors;
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Long orderNum;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 子菜单
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<FlowCategory> children = new ArrayList<>();
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.fuyuanshen.workflow.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 请假对象 test_leave
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-07-21
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("test_leave")
|
||||
public class TestLeave extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 请假类型
|
||||
*/
|
||||
private String leaveType;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startDate;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Date endDate;
|
||||
|
||||
/**
|
||||
* 请假天数
|
||||
*/
|
||||
private Integer leaveDays;
|
||||
|
||||
/**
|
||||
* 请假原因
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* 驳回参数请求
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class BackProcessBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务ID
|
||||
*/
|
||||
@NotNull(message = "任务ID不能为空", groups = AddGroup.class)
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 附件id
|
||||
*/
|
||||
private String fileId;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private List<String> messageType;
|
||||
|
||||
/**
|
||||
* 驳回的节点id(目前未使用,直接驳回到申请人)
|
||||
*/
|
||||
private String nodeCode;
|
||||
|
||||
/**
|
||||
* 办理意见
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 通知
|
||||
*/
|
||||
private String notice;
|
||||
|
||||
/**
|
||||
* 流程变量
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
return new HashMap<>(16);
|
||||
}
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 办理任务请求对象
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class CompleteTaskBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务id
|
||||
*/
|
||||
@NotNull(message = "任务id不能为空", groups = {AddGroup.class})
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 附件id
|
||||
*/
|
||||
private String fileId;
|
||||
|
||||
/**
|
||||
* 抄送人员
|
||||
*/
|
||||
private List<FlowCopyBo> flowCopyList;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private List<String> messageType;
|
||||
|
||||
/**
|
||||
* 办理意见
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 消息通知
|
||||
*/
|
||||
private String notice;
|
||||
|
||||
/**
|
||||
* 流程变量
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* 弹窗选择的办理人
|
||||
*/
|
||||
private Map<String, Object> assigneeMap;
|
||||
|
||||
/**
|
||||
* 扩展变量(此处为逗号分隔的ossId)
|
||||
*/
|
||||
private String ext;
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
return new HashMap<>(16);
|
||||
}
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 撤销任务请求对象
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowCancelBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务ID
|
||||
*/
|
||||
@NotBlank(message = "业务ID不能为空", groups = AddGroup.class)
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 办理意见
|
||||
*/
|
||||
private String message;
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import com.fuyuanshen.workflow.domain.FlowCategory;
|
||||
|
||||
/**
|
||||
* 流程分类业务对象 wf_category
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-06-27
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = FlowCategory.class, reverseConvertGenerate = false)
|
||||
public class FlowCategoryBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 流程分类ID
|
||||
*/
|
||||
@NotNull(message = "流程分类ID不能为空", groups = { EditGroup.class })
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 父流程分类id
|
||||
*/
|
||||
@NotNull(message = "父流程分类id不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
@NotBlank(message = "流程分类名称不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Long orderNum;
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* 抄送
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowCopyBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程实例请求对象
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowInstanceBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程定义名称
|
||||
*/
|
||||
private String flowName;
|
||||
|
||||
/**
|
||||
* 流程定义编码
|
||||
*/
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 任务发起人
|
||||
*/
|
||||
private String startUserId;
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 流程分类id
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 申请人Ids
|
||||
*/
|
||||
private List<Long> createByIds;
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 作废请求对象
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowInvalidBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程实例id
|
||||
*/
|
||||
@NotNull(message = "流程实例id为空", groups = AddGroup.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String comment;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 下一节点信息
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowNextNodeBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 任务id
|
||||
*/
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 流程变量
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
return new HashMap<>(16);
|
||||
}
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务请求对象
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowTaskBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 流程定义名称
|
||||
*/
|
||||
private String flowName;
|
||||
|
||||
/**
|
||||
* 流程定义编码
|
||||
*/
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 流程分类id
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 流程实例id
|
||||
*/
|
||||
private Long instanceId;
|
||||
|
||||
/**
|
||||
* 权限列表
|
||||
*/
|
||||
private List<String> permissionList;
|
||||
|
||||
/**
|
||||
* 申请人Ids
|
||||
*/
|
||||
private List<Long> createByIds;
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 终止任务请求对象
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowTerminationBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务id
|
||||
*/
|
||||
@NotNull(message = "任务id为空", groups = AddGroup.class)
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String comment;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 启动流程对象
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class StartProcessBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 业务唯一值id
|
||||
*/
|
||||
@NotBlank(message = "业务ID不能为空", groups = {AddGroup.class})
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 流程定义编码
|
||||
*/
|
||||
@NotBlank(message = "流程定义编码不能为空", groups = {AddGroup.class})
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
return new HashMap<>(16);
|
||||
}
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 任务操作业务对象,用于描述任务委派、转办、加签等操作的必要参数
|
||||
* 包含了用户ID、任务ID、任务相关的消息、以及加签/减签的用户ID
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Data
|
||||
public class TaskOperationBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 委派/转办人的用户ID(必填,准对委派/转办人操作)
|
||||
*/
|
||||
@NotNull(message = "委派/转办人id不能为空", groups = {AddGroup.class})
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 加签/减签人的用户ID列表(必填,针对加签/减签操作)
|
||||
*/
|
||||
@NotNull(message = "加签/减签id不能为空", groups = {EditGroup.class})
|
||||
private List<String> userIds;
|
||||
|
||||
/**
|
||||
* 任务ID(必填)
|
||||
*/
|
||||
@NotNull(message = "任务id不能为空")
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 意见或备注信息(可选)
|
||||
*/
|
||||
private String message;
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.fuyuanshen.workflow.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import com.fuyuanshen.workflow.domain.TestLeave;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 请假业务对象 test_leave
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-07-21
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = TestLeave.class, reverseConvertGenerate = false)
|
||||
public class TestLeaveBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 请假类型
|
||||
*/
|
||||
@NotBlank(message = "请假类型不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String leaveType;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
@NotNull(message = "开始时间不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date startDate;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
@NotNull(message = "结束时间不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date endDate;
|
||||
|
||||
/**
|
||||
* 请假天数
|
||||
*/
|
||||
private Integer leaveDays;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Integer startLeaveDays;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Integer endLeaveDays;
|
||||
|
||||
/**
|
||||
* 请假原因
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 按钮权限
|
||||
*
|
||||
* @author may
|
||||
* @date 2025-02-28
|
||||
*/
|
||||
@Data
|
||||
public class ButtonPermissionVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 唯一编码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 选项值
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* 是否显示
|
||||
*/
|
||||
private Boolean show;
|
||||
|
||||
public ButtonPermissionVo() {
|
||||
}
|
||||
|
||||
public ButtonPermissionVo(String code, Boolean show) {
|
||||
this.code = code;
|
||||
this.show = show;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package com.fuyuanshen.workflow.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.workflow.domain.FlowCategory;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 流程分类视图对象 wf_category
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-06-27
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = FlowCategory.class)
|
||||
public class FlowCategoryVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程分类ID
|
||||
*/
|
||||
@ExcelProperty(value = "流程分类ID")
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 父类别名称
|
||||
*/
|
||||
private String parentName;
|
||||
|
||||
/**
|
||||
* 祖级列表
|
||||
*/
|
||||
private String ancestors;
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程分类名称")
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
@ExcelProperty(value = "显示顺序")
|
||||
private Long orderNum;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 子菜单
|
||||
*/
|
||||
private List<FlowCategoryVo> children = new ArrayList<>();
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package com.fuyuanshen.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.translation.annotation.Translation;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程定义视图
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowDefinitionVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 删除标记
|
||||
*/
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 流程定义编码
|
||||
*/
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 流程定义名称
|
||||
*/
|
||||
private String flowName;
|
||||
|
||||
/**
|
||||
* 流程分类id
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
@Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 流程版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 是否发布(0未发布 1已发布 9失效)
|
||||
*/
|
||||
private Integer isPublish;
|
||||
|
||||
/**
|
||||
* 审批表单是否自定义(Y是 N否)
|
||||
*/
|
||||
private String formCustom;
|
||||
|
||||
/**
|
||||
* 审批表单路径
|
||||
*/
|
||||
private String formPath;
|
||||
|
||||
/**
|
||||
* 流程激活状态(0挂起 1激活)
|
||||
*/
|
||||
private Integer activityStatus;
|
||||
|
||||
/**
|
||||
* 监听器类型
|
||||
*/
|
||||
private String listenerType;
|
||||
|
||||
/**
|
||||
* 监听器路径
|
||||
*/
|
||||
private String listenerPath;
|
||||
|
||||
/**
|
||||
* 扩展字段,预留给业务系统使用
|
||||
*/
|
||||
private String ext;
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
package com.fuyuanshen.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.core.utils.DateUtils;
|
||||
import com.fuyuanshen.common.translation.annotation.Translation;
|
||||
import com.fuyuanshen.common.translation.constant.TransConstant;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import org.dromara.warm.flow.core.enums.CooperateType;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 历史任务视图
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowHisTaskVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 删除标记
|
||||
*/
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 对应flow_definition表的id
|
||||
*/
|
||||
private Long definitionId;
|
||||
|
||||
/**
|
||||
* 流程定义名称
|
||||
*/
|
||||
private String flowName;
|
||||
|
||||
/**
|
||||
* 流程实例表id
|
||||
*/
|
||||
private Long instanceId;
|
||||
|
||||
/**
|
||||
* 任务表id
|
||||
*/
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)
|
||||
*/
|
||||
private Integer cooperateType;
|
||||
|
||||
/**
|
||||
* 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)
|
||||
*/
|
||||
private String cooperateTypeName;
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 开始节点编码
|
||||
*/
|
||||
private String nodeCode;
|
||||
|
||||
/**
|
||||
* 开始节点名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)
|
||||
*/
|
||||
private Integer nodeType;
|
||||
|
||||
/**
|
||||
* 目标节点编码
|
||||
*/
|
||||
private String targetNodeCode;
|
||||
|
||||
/**
|
||||
* 结束节点名称
|
||||
*/
|
||||
private String targetNodeName;
|
||||
|
||||
/**
|
||||
* 审批者
|
||||
*/
|
||||
private String approver;
|
||||
|
||||
/**
|
||||
* 审批者
|
||||
*/
|
||||
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "approver")
|
||||
private String approveName;
|
||||
|
||||
/**
|
||||
* 协作人(只有转办、会签、票签、委派)
|
||||
*/
|
||||
private String collaborator;
|
||||
|
||||
/**
|
||||
* 权限标识 permissionFlag的list形式
|
||||
*/
|
||||
private List<String> permissionList;
|
||||
|
||||
/**
|
||||
* 跳转类型(PASS通过 REJECT退回 NONE无动作)
|
||||
*/
|
||||
private String skipType;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
private String flowStatus;
|
||||
|
||||
/**
|
||||
* 任务状态
|
||||
*/
|
||||
private String flowTaskStatus;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
private String flowStatusName;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 业务详情 存业务类的json
|
||||
*/
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 申请人
|
||||
*/
|
||||
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy")
|
||||
private String createByName;
|
||||
|
||||
/**
|
||||
* 流程分类id
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
@Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 审批表单是否自定义(Y是 N否)
|
||||
*/
|
||||
private String formCustom;
|
||||
|
||||
/**
|
||||
* 审批表单路径
|
||||
*/
|
||||
private String formPath;
|
||||
|
||||
/**
|
||||
* 流程定义编码
|
||||
*/
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 流程版本号
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 运行时长
|
||||
*/
|
||||
private String runDuration;
|
||||
|
||||
/**
|
||||
* 设置创建时间并计算任务运行时长
|
||||
*
|
||||
* @param createTime 创建时间
|
||||
*/
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
updateRunDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置更新时间并计算任务运行时长
|
||||
*
|
||||
* @param updateTime 更新时间
|
||||
*/
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
updateRunDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新运行时长
|
||||
*/
|
||||
private void updateRunDuration() {
|
||||
// 如果创建时间和更新时间均不为空,计算它们之间的时长
|
||||
if (this.updateTime != null && this.createTime != null) {
|
||||
this.runDuration = DateUtils.getTimeDifference(this.updateTime, this.createTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置协作方式,并通过协作方式获取名称
|
||||
*/
|
||||
public void setCooperateType(Integer cooperateType) {
|
||||
this.cooperateType = cooperateType;
|
||||
this.cooperateTypeName = CooperateType.getValueByKey(cooperateType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package com.fuyuanshen.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.translation.annotation.Translation;
|
||||
import com.fuyuanshen.common.translation.constant.TransConstant;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程实例视图
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowInstanceVo {
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 删除标记
|
||||
*/
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 对应flow_definition表的id
|
||||
*/
|
||||
private Long definitionId;
|
||||
|
||||
/**
|
||||
* 流程定义名称
|
||||
*/
|
||||
private String flowName;
|
||||
|
||||
/**
|
||||
* 流程定义编码
|
||||
*/
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)
|
||||
*/
|
||||
private Integer nodeType;
|
||||
|
||||
/**
|
||||
* 流程节点编码 每个流程的nodeCode是唯一的,即definitionId+nodeCode唯一,在数据库层面做了控制
|
||||
*/
|
||||
private String nodeCode;
|
||||
|
||||
/**
|
||||
* 流程节点名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 流程变量
|
||||
*/
|
||||
private String variable;
|
||||
|
||||
/**
|
||||
* 流程状态(0待提交 1审批中 2 审批通过 3自动通过 8已完成 9已退回 10失效)
|
||||
*/
|
||||
private String flowStatus;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
private String flowStatusName;
|
||||
|
||||
/**
|
||||
* 流程激活状态(0挂起 1激活)
|
||||
*/
|
||||
private Integer activityStatus;
|
||||
|
||||
/**
|
||||
* 审批表单是否自定义(Y是 N否)
|
||||
*/
|
||||
private String formCustom;
|
||||
|
||||
/**
|
||||
* 审批表单路径
|
||||
*/
|
||||
private String formPath;
|
||||
|
||||
/**
|
||||
* 扩展字段,预留给业务系统使用
|
||||
*/
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* 流程定义版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 申请人
|
||||
*/
|
||||
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy")
|
||||
private String createByName;
|
||||
|
||||
/**
|
||||
* 流程分类id
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
@Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
|
||||
private String categoryName;
|
||||
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
package com.fuyuanshen.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.common.translation.annotation.Translation;
|
||||
import com.fuyuanshen.common.translation.constant.TransConstant;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import org.dromara.warm.flow.core.entity.User;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务视图
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class FlowTaskVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 删除标记
|
||||
*/
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 对应flow_definition表的id
|
||||
*/
|
||||
private Long definitionId;
|
||||
|
||||
/**
|
||||
* 流程实例表id
|
||||
*/
|
||||
private Long instanceId;
|
||||
|
||||
/**
|
||||
* 流程定义名称
|
||||
*/
|
||||
private String flowName;
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 节点编码
|
||||
*/
|
||||
private String nodeCode;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)
|
||||
*/
|
||||
private Integer nodeType;
|
||||
|
||||
/**
|
||||
* 权限标识 permissionFlag的list形式
|
||||
*/
|
||||
private List<String> permissionList;
|
||||
|
||||
/**
|
||||
* 流程用户列表
|
||||
*/
|
||||
private List<User> userList;
|
||||
|
||||
/**
|
||||
* 审批表单是否自定义(Y是 N否)
|
||||
*/
|
||||
private String formCustom;
|
||||
|
||||
/**
|
||||
* 审批表单
|
||||
*/
|
||||
private String formPath;
|
||||
|
||||
/**
|
||||
* 流程定义编码
|
||||
*/
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 流程版本号
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
private String flowStatus;
|
||||
|
||||
/**
|
||||
* 流程分类id
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 流程分类名称
|
||||
*/
|
||||
@Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
@Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "flowStatus", other = "wf_business_status")
|
||||
private String flowStatusName;
|
||||
|
||||
/**
|
||||
* 办理人类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 办理人ids
|
||||
*/
|
||||
private String assigneeIds;
|
||||
|
||||
/**
|
||||
* 办理人名称
|
||||
*/
|
||||
private String assigneeNames;
|
||||
|
||||
/**
|
||||
* 抄送人id
|
||||
*/
|
||||
private String processedBy;
|
||||
|
||||
/**
|
||||
* 抄送人名称
|
||||
*/
|
||||
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "processedBy")
|
||||
private String processedByName;
|
||||
|
||||
/**
|
||||
* 流程签署比例值 大于0为票签,会签
|
||||
*/
|
||||
private BigDecimal nodeRatio;
|
||||
|
||||
/**
|
||||
* 申请人id
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 申请人名称
|
||||
*/
|
||||
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy")
|
||||
private String createByName;
|
||||
|
||||
/**
|
||||
* 是否为申请人节点
|
||||
*/
|
||||
private Boolean applyNode;
|
||||
|
||||
/**
|
||||
* 按钮权限
|
||||
*/
|
||||
private List<ButtonPermissionVo> buttonList;
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package com.fuyuanshen.workflow.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.workflow.domain.TestLeave;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 请假视图对象 test_leave
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-07-21
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = TestLeave.class)
|
||||
public class TestLeaveVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 请假类型
|
||||
*/
|
||||
@ExcelProperty(value = "请假类型")
|
||||
private String leaveType;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
@ExcelProperty(value = "开始时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date startDate;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
@ExcelProperty(value = "结束时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date endDate;
|
||||
|
||||
/**
|
||||
* 请假天数
|
||||
*/
|
||||
@ExcelProperty(value = "请假天数")
|
||||
private Integer leaveDays;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "请假原因")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@ExcelProperty(value = "状态")
|
||||
private String status;
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.fuyuanshen.workflow.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.domain.event.ProcessTaskEvent;
|
||||
import com.fuyuanshen.common.core.domain.event.ProcessDeleteEvent;
|
||||
import com.fuyuanshen.common.core.domain.event.ProcessEvent;
|
||||
import com.fuyuanshen.common.core.utils.SpringUtils;
|
||||
import com.fuyuanshen.common.tenant.helper.TenantHelper;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程监听服务
|
||||
*
|
||||
* @author may
|
||||
* @date 2024-06-02
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FlowProcessEventHandler {
|
||||
|
||||
/**
|
||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
||||
*
|
||||
* @param flowCode 流程定义编码
|
||||
* @param instance 实例数据
|
||||
* @param status 流程状态
|
||||
* @param params 办理参数
|
||||
* @param submit 当为true时为申请人节点办理
|
||||
*/
|
||||
public void processHandler(String flowCode, Instance instance, String status, Map<String, Object> params, boolean submit) {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
log.info("【流程事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 流程状态: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 是否申请人节点: {}, 参数: {}",
|
||||
tenantId, flowCode, instance.getBusinessId(), status, instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), submit, params);
|
||||
ProcessEvent processEvent = new ProcessEvent();
|
||||
processEvent.setTenantId(tenantId);
|
||||
processEvent.setFlowCode(flowCode);
|
||||
processEvent.setBusinessId(instance.getBusinessId());
|
||||
processEvent.setNodeType(instance.getNodeType());
|
||||
processEvent.setNodeCode(instance.getNodeCode());
|
||||
processEvent.setNodeName(instance.getNodeName());
|
||||
processEvent.setStatus(status);
|
||||
processEvent.setParams(params);
|
||||
processEvent.setSubmit(submit);
|
||||
SpringUtils.context().publishEvent(processEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行创建任务监听
|
||||
*
|
||||
* @param flowCode 流程定义编码
|
||||
* @param instance 实例数据
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
public void processTaskHandler(String flowCode, Instance instance, Long taskId) {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
log.info("【流程任务事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 任务ID: {}",
|
||||
tenantId, flowCode, instance.getBusinessId(), instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), taskId);
|
||||
ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
|
||||
processTaskEvent.setTenantId(tenantId);
|
||||
processTaskEvent.setFlowCode(flowCode);
|
||||
processTaskEvent.setBusinessId(instance.getBusinessId());
|
||||
processTaskEvent.setNodeType(instance.getNodeType());
|
||||
processTaskEvent.setNodeCode(instance.getNodeCode());
|
||||
processTaskEvent.setNodeName(instance.getNodeName());
|
||||
processTaskEvent.setTaskId(taskId);
|
||||
processTaskEvent.setStatus(instance.getFlowStatus());
|
||||
SpringUtils.context().publishEvent(processTaskEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程监听
|
||||
*
|
||||
* @param flowCode 流程定义编码
|
||||
* @param businessId 业务ID
|
||||
*/
|
||||
public void processDeleteHandler(String flowCode, String businessId) {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
log.info("【流程删除事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}", tenantId, flowCode, businessId);
|
||||
ProcessDeleteEvent processDeleteEvent = new ProcessDeleteEvent();
|
||||
processDeleteEvent.setTenantId(tenantId);
|
||||
processDeleteEvent.setFlowCode(flowCode);
|
||||
processDeleteEvent.setBusinessId(businessId);
|
||||
SpringUtils.context().publishEvent(processDeleteEvent);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.fuyuanshen.workflow.handler;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.handler.PermissionHandler;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.service.IFlwCommonService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 办理人权限处理器
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@Slf4j
|
||||
public class WorkflowPermissionHandler implements PermissionHandler {
|
||||
|
||||
private final IFlwCommonService flwCommonService;
|
||||
|
||||
/**
|
||||
* 办理人权限标识,比如用户,角色,部门等,用于校验是否有权限办理任务
|
||||
* 后续在{@link FlowParams#getPermissionFlag} 中获取
|
||||
* 返回当前用户权限集合
|
||||
*/
|
||||
@Override
|
||||
public List<String> permissions() {
|
||||
return Collections.singletonList(LoginHelper.getUserIdStr());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前办理人
|
||||
*
|
||||
* @return 当前办理人
|
||||
*/
|
||||
@Override
|
||||
public String getHandler() {
|
||||
return LoginHelper.getUserIdStr();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换办理人,比如设计器中预设了能办理的人,如果其中包含角色或者部门id等,可以通过此接口进行转换成用户id
|
||||
*/
|
||||
@Override
|
||||
public List<String> convertPermissions(List<String> permissions) {
|
||||
if (CollUtil.isNotEmpty(permissions)) {
|
||||
permissions = flwCommonService.buildUser(permissions);
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
package com.fuyuanshen.workflow.listener;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.enums.BusinessStatusEnum;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import org.dromara.warm.flow.core.FlowEngine;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.entity.Definition;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.core.listener.GlobalListener;
|
||||
import org.dromara.warm.flow.core.listener.ListenerVariable;
|
||||
import org.dromara.warm.flow.core.service.InsService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import com.fuyuanshen.workflow.common.enums.TaskStatusEnum;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowCopyBo;
|
||||
import com.fuyuanshen.workflow.handler.FlowProcessEventHandler;
|
||||
import com.fuyuanshen.workflow.service.IFlwCommonService;
|
||||
import com.fuyuanshen.workflow.service.IFlwInstanceService;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 全局任务办理监听
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class WorkflowGlobalListener implements GlobalListener {
|
||||
|
||||
private final IFlwTaskService flwTaskService;
|
||||
private final IFlwInstanceService instanceService;
|
||||
private final FlowProcessEventHandler flowProcessEventHandler;
|
||||
private final IFlwCommonService flwCommonService;
|
||||
private final InsService insService;
|
||||
|
||||
/**
|
||||
* 创建监听器,任务创建时执行
|
||||
*
|
||||
* @param listenerVariable 监听器变量
|
||||
*/
|
||||
@Override
|
||||
public void create(ListenerVariable listenerVariable) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始监听器,任务开始办理时执行
|
||||
*
|
||||
* @param listenerVariable 监听器变量
|
||||
*/
|
||||
@Override
|
||||
public void start(ListenerVariable listenerVariable) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分派监听器,动态修改代办任务信息
|
||||
*
|
||||
* @param listenerVariable 监听器变量
|
||||
*/
|
||||
@Override
|
||||
public void assignment(ListenerVariable listenerVariable) {
|
||||
Map<String, Object> variable = listenerVariable.getVariable();
|
||||
List<Task> nextTasks = listenerVariable.getNextTasks();
|
||||
FlowParams flowParams = listenerVariable.getFlowParams();
|
||||
Definition definition = listenerVariable.getDefinition();
|
||||
Instance instance = listenerVariable.getInstance();
|
||||
String applyNodeCode = flwCommonService.applyNodeCode(definition.getId());
|
||||
for (Task flowTask : nextTasks) {
|
||||
// 如果办理或者退回并行存在需要指定办理人,则直接覆盖办理人
|
||||
if (variable.containsKey(flowTask.getNodeCode()) && (TaskStatusEnum.PASS.getStatus().equals(flowParams.getHisStatus())
|
||||
|| TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus()))) {
|
||||
String userIds = variable.get(flowTask.getNodeCode()).toString();
|
||||
flowTask.setPermissionList(List.of(userIds.split(StringUtils.SEPARATOR)));
|
||||
variable.remove(flowTask.getNodeCode());
|
||||
}
|
||||
// 如果是申请节点,则把启动人添加到办理人
|
||||
if (flowTask.getNodeCode().equals(applyNodeCode)) {
|
||||
flowTask.setPermissionList(List.of(instance.getCreateBy()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成监听器,当前任务完成后执行
|
||||
*
|
||||
* @param listenerVariable 监听器变量
|
||||
*/
|
||||
@Override
|
||||
public void finish(ListenerVariable listenerVariable) {
|
||||
Instance instance = listenerVariable.getInstance();
|
||||
Definition definition = listenerVariable.getDefinition();
|
||||
Task task = listenerVariable.getTask();
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
FlowParams flowParams = listenerVariable.getFlowParams();
|
||||
Map<String, Object> variable = new HashMap<>();
|
||||
if (ObjectUtil.isNotNull(flowParams)) {
|
||||
// 历史任务扩展(通常为附件)
|
||||
params.put("hisTaskExt", flowParams.getHisTaskExt());
|
||||
// 办理人
|
||||
params.put("handler", flowParams.getHandler());
|
||||
// 办理意见
|
||||
params.put("message", flowParams.getMessage());
|
||||
variable = flowParams.getVariable();
|
||||
}
|
||||
//申请人提交事件
|
||||
Boolean submit = MapUtil.getBool(variable, FlowConstant.SUBMIT);
|
||||
if (submit != null && submit) {
|
||||
flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, instance.getFlowStatus(), variable, true);
|
||||
} else {
|
||||
// 判断流程状态(发布:撤销,退回,作废,终止,已完成事件)
|
||||
String status = determineFlowStatus(instance);
|
||||
if (StringUtils.isNotBlank(status)) {
|
||||
flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, params, false);
|
||||
}
|
||||
}
|
||||
//发布任务事件
|
||||
if (task != null) {
|
||||
flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, task.getId());
|
||||
}
|
||||
if (ObjectUtil.isNull(flowParams)) {
|
||||
return;
|
||||
}
|
||||
// 只有办理或者退回的时候才执行消息通知和抄送
|
||||
if (TaskStatusEnum.PASS.getStatus().equals(flowParams.getHisStatus())
|
||||
|| TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus())) {
|
||||
if (variable != null) {
|
||||
if (variable.containsKey(FlowConstant.FLOW_COPY_LIST)) {
|
||||
List<FlowCopyBo> flowCopyList = (List<FlowCopyBo>) variable.get(FlowConstant.FLOW_COPY_LIST);
|
||||
// 添加抄送人
|
||||
flwTaskService.setCopy(task, flowCopyList);
|
||||
}
|
||||
if (variable.containsKey(FlowConstant.MESSAGE_TYPE)) {
|
||||
List<String> messageType = (List<String>) variable.get(FlowConstant.MESSAGE_TYPE);
|
||||
String notice = (String) variable.get(FlowConstant.MESSAGE_NOTICE);
|
||||
// 消息通知
|
||||
if (CollUtil.isNotEmpty(messageType)) {
|
||||
flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
|
||||
}
|
||||
}
|
||||
FlowInstance ins = new FlowInstance();
|
||||
Map<String, Object> variableMap = instance.getVariableMap();
|
||||
variableMap.remove(FlowConstant.FLOW_COPY_LIST);
|
||||
variableMap.remove(FlowConstant.MESSAGE_TYPE);
|
||||
variableMap.remove(FlowConstant.MESSAGE_NOTICE);
|
||||
variableMap.remove(FlowConstant.SUBMIT);
|
||||
ins.setId(instance.getId());
|
||||
ins.setVariable(FlowEngine.jsonConvert.objToStr(variableMap));
|
||||
insService.updateById(ins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流程实例确定最终状态
|
||||
*
|
||||
* @param instance 流程实例
|
||||
* @return 流程最终状态
|
||||
*/
|
||||
private String determineFlowStatus(Instance instance) {
|
||||
String flowStatus = instance.getFlowStatus();
|
||||
if (StringUtils.isNotBlank(flowStatus) && BusinessStatusEnum.initialState(flowStatus)) {
|
||||
log.info("流程实例当前状态: {}", flowStatus);
|
||||
return flowStatus;
|
||||
} else {
|
||||
Long instanceId = instance.getId();
|
||||
List<FlowTask> flowTasks = flwTaskService.selectByInstId(instanceId);
|
||||
if (CollUtil.isEmpty(flowTasks)) {
|
||||
String status = BusinessStatusEnum.FINISH.getStatus();
|
||||
// 更新流程状态为已完成
|
||||
instanceService.updateStatus(instanceId, status);
|
||||
log.info("流程已结束,状态更新为: {}", status);
|
||||
return status;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.fuyuanshen.workflow.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.fuyuanshen.common.mybatis.annotation.DataColumn;
|
||||
import com.fuyuanshen.common.mybatis.annotation.DataPermission;
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.fuyuanshen.common.mybatis.helper.DataBaseHelper;
|
||||
import com.fuyuanshen.workflow.domain.FlowCategory;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowCategoryVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 流程分类Mapper接口
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-06-27
|
||||
*/
|
||||
public interface FlwCategoryMapper extends BaseMapperPlus<FlowCategory, FlowCategoryVo> {
|
||||
|
||||
/**
|
||||
* 统计指定流程分类ID的分类数量
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
* @return 该流程分类ID的分类数量
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "createDept")
|
||||
})
|
||||
long countCategoryById(Long categoryId);
|
||||
|
||||
/**
|
||||
* 根据父流程分类ID查询其所有子流程分类的列表
|
||||
*
|
||||
* @param parentId 父流程分类ID
|
||||
* @return 包含子流程分类的列表
|
||||
*/
|
||||
default List<FlowCategory> selectListByParentId(Long parentId) {
|
||||
return this.selectList(new LambdaQueryWrapper<FlowCategory>()
|
||||
.select(FlowCategory::getCategoryId)
|
||||
.apply(DataBaseHelper.findInSet(parentId, "ancestors")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据父流程分类ID查询包括父ID及其所有子流程分类ID的列表
|
||||
*
|
||||
* @param parentId 父流程分类ID
|
||||
* @return 包含父ID和子流程分类ID的列表
|
||||
*/
|
||||
default List<Long> selectCategoryIdsByParentId(Long parentId) {
|
||||
return Stream.concat(
|
||||
this.selectListByParentId(parentId).stream()
|
||||
.map(FlowCategory::getCategoryId),
|
||||
Stream.of(parentId)
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.fuyuanshen.workflow.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowInstanceBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowInstanceVo;
|
||||
|
||||
/**
|
||||
* 实例信息Mapper接口
|
||||
*
|
||||
* @author may
|
||||
* @date 2024-03-02
|
||||
*/
|
||||
public interface FlwInstanceMapper {
|
||||
|
||||
/**
|
||||
* 流程实例信息
|
||||
*
|
||||
* @param page 分页
|
||||
* @param queryWrapper 条件
|
||||
* @return 结果
|
||||
*/
|
||||
Page<FlowInstanceVo> selectInstanceList(@Param("page") Page<FlowInstanceVo> page, @Param(Constants.WRAPPER) Wrapper<FlowInstanceBo> queryWrapper);
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.fuyuanshen.workflow.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowTaskBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowHisTaskVo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowTaskVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 任务信息Mapper接口
|
||||
*
|
||||
* @author may
|
||||
* @date 2024-03-02
|
||||
*/
|
||||
public interface FlwTaskMapper {
|
||||
|
||||
/**
|
||||
* 获取待办信息
|
||||
*
|
||||
* @param page 分页
|
||||
* @param queryWrapper 条件
|
||||
* @return 结果
|
||||
*/
|
||||
Page<FlowTaskVo> getListRunTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||
|
||||
/**
|
||||
* 获取待办信息
|
||||
*
|
||||
* @param queryWrapper 条件
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowTaskVo> getListRunTask(@Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||
|
||||
/**
|
||||
* 获取已办
|
||||
*
|
||||
* @param page 分页
|
||||
* @param queryWrapper 条件
|
||||
* @return 结果
|
||||
*/
|
||||
Page<FlowHisTaskVo> getListFinishTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||
|
||||
/**
|
||||
* 查询当前用户的抄送
|
||||
*
|
||||
* @param page 分页
|
||||
* @param queryWrapper 条件
|
||||
* @return 结果
|
||||
*/
|
||||
Page<FlowTaskVo> getTaskCopyByPage(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) QueryWrapper<FlowTaskBo> queryWrapper);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.fuyuanshen.workflow.mapper;
|
||||
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.fuyuanshen.workflow.domain.TestLeave;
|
||||
import com.fuyuanshen.workflow.domain.vo.TestLeaveVo;
|
||||
|
||||
/**
|
||||
* 请假Mapper接口
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-07-21
|
||||
*/
|
||||
public interface TestLeaveMapper extends BaseMapperPlus<TestLeave, TestLeaveVo> {
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowCategoryBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowCategoryVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程分类Service接口
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
public interface IFlwCategoryService {
|
||||
|
||||
/**
|
||||
* 查询流程分类
|
||||
*
|
||||
* @param categoryId 主键
|
||||
* @return 流程分类
|
||||
*/
|
||||
FlowCategoryVo queryById(Long categoryId);
|
||||
|
||||
/**
|
||||
* 根据流程分类ID查询流程分类名称
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
* @return 流程分类名称
|
||||
*/
|
||||
String selectCategoryNameById(Long categoryId);
|
||||
|
||||
/**
|
||||
* 查询符合条件的流程分类列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 流程分类列表
|
||||
*/
|
||||
List<FlowCategoryVo> queryList(FlowCategoryBo bo);
|
||||
|
||||
/**
|
||||
* 查询流程分类树结构信息
|
||||
*
|
||||
* @param category 流程分类信息
|
||||
* @return 流程分类树信息集合
|
||||
*/
|
||||
List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category);
|
||||
|
||||
/**
|
||||
* 校验流程分类是否有数据权限
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
*/
|
||||
void checkCategoryDataScope(Long categoryId);
|
||||
|
||||
/**
|
||||
* 校验流程分类名称是否唯一
|
||||
*
|
||||
* @param category 流程分类信息
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkCategoryNameUnique(FlowCategoryBo category);
|
||||
|
||||
/**
|
||||
* 查询流程分类是否存在流程定义
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
* @return 结果 true 存在 false 不存在
|
||||
*/
|
||||
boolean checkCategoryExistDefinition(Long categoryId);
|
||||
|
||||
/**
|
||||
* 是否存在流程分类子节点
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
* @return 结果
|
||||
*/
|
||||
boolean hasChildByCategoryId(Long categoryId);
|
||||
|
||||
/**
|
||||
* 新增流程分类
|
||||
*
|
||||
* @param bo 流程分类
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
int insertByBo(FlowCategoryBo bo);
|
||||
|
||||
/**
|
||||
* 修改流程分类
|
||||
*
|
||||
* @param bo 流程分类
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
int updateByBo(FlowCategoryBo bo);
|
||||
|
||||
/**
|
||||
* 删除流程分类信息
|
||||
*
|
||||
* @param categoryId 主键
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
int deleteWithValidById(Long categoryId);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用 工作流服务
|
||||
*
|
||||
* @author LionLi
|
||||
*/
|
||||
public interface IFlwCommonService {
|
||||
|
||||
/**
|
||||
* 构建工作流用户
|
||||
*
|
||||
* @param permissionList 办理用户
|
||||
* @return 用户
|
||||
*/
|
||||
List<String> buildUser(List<String> permissionList);
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param flowName 流程定义名称
|
||||
* @param instId 实例id
|
||||
* @param messageType 消息类型
|
||||
* @param message 消息内容,为空则发送默认配置的消息内容
|
||||
*/
|
||||
void sendMessage(String flowName, Long instId, List<String> messageType, String message);
|
||||
|
||||
/**
|
||||
* 申请人节点编码
|
||||
*
|
||||
* @param definitionId 流程定义id
|
||||
* @return 申请人节点编码
|
||||
*/
|
||||
String applyNodeCode(Long definitionId);
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowDefinitionVo;
|
||||
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程定义 服务层
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
public interface IFlwDefinitionService {
|
||||
|
||||
/**
|
||||
* 查询流程定义列表
|
||||
*
|
||||
* @param flowDefinition 参数
|
||||
* @param pageQuery 分页
|
||||
* @return 返回分页列表
|
||||
*/
|
||||
TableDataInfo<FlowDefinitionVo> queryList(FlowDefinition flowDefinition, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询未发布的流程定义列表
|
||||
*
|
||||
* @param flowDefinition 参数
|
||||
* @param pageQuery 分页
|
||||
* @return 返回分页列表
|
||||
*/
|
||||
TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery);
|
||||
|
||||
|
||||
/**
|
||||
* 发布流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
* @return 结果
|
||||
*/
|
||||
boolean publish(Long id);
|
||||
|
||||
/**
|
||||
* 导出流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
* @param response 响应
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
void exportDef(Long id, HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 导入流程定义
|
||||
*
|
||||
* @param file 文件
|
||||
* @param category 分类
|
||||
* @return 结果
|
||||
*/
|
||||
boolean importJson(MultipartFile file, String category);
|
||||
|
||||
/**
|
||||
* 删除流程定义
|
||||
*
|
||||
* @param ids 流程定义id
|
||||
* @return 结果
|
||||
*/
|
||||
boolean removeDef(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 新增租户流程定义
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
*/
|
||||
void syncDef(String tenantId);
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowCancelBo;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowInstanceBo;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowInvalidBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowInstanceVo;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程实例 服务层
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
public interface IFlwInstanceService {
|
||||
|
||||
/**
|
||||
* 分页查询正在运行的流程实例
|
||||
*
|
||||
* @param flowInstanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowInstanceVo> selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 分页查询已结束的流程实例
|
||||
*
|
||||
* @param flowInstanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowInstanceVo> selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 根据业务id查询流程实例详细信息
|
||||
*
|
||||
* @param businessId 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
FlowInstanceVo queryByBusinessId(Long businessId);
|
||||
|
||||
/**
|
||||
* 按照业务id查询流程实例
|
||||
*
|
||||
* @param businessId 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
FlowInstance selectInstByBusinessId(String businessId);
|
||||
|
||||
/**
|
||||
* 按照实例id查询流程实例
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
* @return 结果
|
||||
*/
|
||||
FlowInstance selectInstById(Long instanceId);
|
||||
|
||||
/**
|
||||
* 按照实例id查询流程实例
|
||||
*
|
||||
* @param instanceIds 实例id
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowInstance> selectInstListByIdList(List<Long> instanceIds);
|
||||
|
||||
/**
|
||||
* 按照业务id删除流程实例
|
||||
*
|
||||
* @param businessIds 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
boolean deleteByBusinessIds(List<Long> businessIds);
|
||||
|
||||
/**
|
||||
* 按照实例id删除流程实例
|
||||
*
|
||||
* @param instanceIds 实例id
|
||||
* @return 结果
|
||||
*/
|
||||
boolean deleteByInstanceIds(List<Long> instanceIds);
|
||||
|
||||
/**
|
||||
* 撤销流程
|
||||
*
|
||||
* @param bo 参数
|
||||
* @return 结果
|
||||
*/
|
||||
boolean cancelProcessApply(FlowCancelBo bo);
|
||||
|
||||
/**
|
||||
* 获取当前登陆人发起的流程实例
|
||||
*
|
||||
* @param instanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 获取流程图,流程记录
|
||||
*
|
||||
* @param businessId 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
Map<String, Object> flowHisTaskList(String businessId);
|
||||
|
||||
/**
|
||||
* 按照实例id更新状态
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
* @param status 状态
|
||||
*/
|
||||
void updateStatus(Long instanceId, String status);
|
||||
|
||||
/**
|
||||
* 获取流程变量
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
* @return 结果
|
||||
*/
|
||||
Map<String, Object> instanceVariable(Long instanceId);
|
||||
|
||||
/**
|
||||
* 设置流程变量
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
* @param variable 流程变量
|
||||
*/
|
||||
void setVariable(Long instanceId, Map<String, Object> variable);
|
||||
|
||||
/**
|
||||
* 按任务id查询实例
|
||||
*
|
||||
* @param taskId 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
FlowInstance selectByTaskId(Long taskId);
|
||||
|
||||
/**
|
||||
* 按任务id查询实例
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowInstance> selectByTaskIdList(List<Long> taskIdList);
|
||||
|
||||
/**
|
||||
* 作废流程
|
||||
*
|
||||
* @param bo 流程实例
|
||||
* @return 结果
|
||||
*/
|
||||
boolean processInvalid(FlowInvalidBo bo);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import com.fuyuanshen.workflow.domain.vo.ButtonPermissionVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程节点扩展属性 服务层
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
public interface IFlwNodeExtService {
|
||||
|
||||
/**
|
||||
* 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
|
||||
*
|
||||
* @param ext 扩展属性 JSON 字符串
|
||||
* @return 按钮权限 VO 列表
|
||||
*/
|
||||
List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext);
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import com.fuyuanshen.common.core.domain.dto.UserDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程设计器-获取办理人
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
public interface IFlwTaskAssigneeService {
|
||||
|
||||
/**
|
||||
* 批量解析多个存储标识符(storageIds),按类型分类并合并查询用户列表
|
||||
* 输入格式支持多个以逗号分隔的标识(如 "user:123,role:456,789")
|
||||
* 会自动去重返回结果,非法格式的标识将被忽略
|
||||
*
|
||||
* @param storageIds 多个存储标识符字符串(逗号分隔)
|
||||
* @return 合并后的用户列表,去重后返回,非法格式的标识将被跳过
|
||||
*/
|
||||
List<UserDTO> fetchUsersByStorageIds(String storageIds);
|
||||
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import com.fuyuanshen.common.core.domain.dto.StartProcessReturnDTO;
|
||||
import com.fuyuanshen.common.core.domain.dto.UserDTO;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.workflow.domain.bo.*;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowHisTaskVo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowTaskVo;
|
||||
import org.dromara.warm.flow.core.entity.Node;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.orm.entity.FlowHisTask;
|
||||
import org.dromara.warm.flow.orm.entity.FlowNode;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 任务 服务层
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
public interface IFlwTaskService {
|
||||
|
||||
/**
|
||||
* 启动任务
|
||||
*
|
||||
* @param startProcessBo 启动流程参数
|
||||
* @return 结果
|
||||
*/
|
||||
StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo);
|
||||
|
||||
/**
|
||||
* 办理任务
|
||||
*
|
||||
* @param completeTaskBo 办理任务参数
|
||||
* @return 结果
|
||||
*/
|
||||
boolean completeTask(CompleteTaskBo completeTaskBo);
|
||||
|
||||
/**
|
||||
* 添加抄送人
|
||||
*
|
||||
* @param task 任务信息
|
||||
* @param flowCopyList 抄送人
|
||||
*/
|
||||
void setCopy(Task task, List<FlowCopyBo> flowCopyList);
|
||||
|
||||
/**
|
||||
* 查询当前用户的待办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询当前租户所有待办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询待办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询已办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询当前用户的抄送
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
* @return 结果
|
||||
*/
|
||||
TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 修改任务办理人
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @param userId 用户id
|
||||
* @return 结果
|
||||
*/
|
||||
boolean updateAssignee(List<Long> taskIdList, String userId);
|
||||
|
||||
/**
|
||||
* 驳回审批
|
||||
*
|
||||
* @param bo 参数
|
||||
* @return 结果
|
||||
*/
|
||||
boolean backProcess(BackProcessBo bo);
|
||||
|
||||
/**
|
||||
* 获取可驳回的前置节点
|
||||
*
|
||||
* @param definitionId 流程定义id
|
||||
* @param nowNodeCode 当前节点
|
||||
* @return 结果
|
||||
*/
|
||||
List<Node> getBackTaskNode(Long definitionId, String nowNodeCode);
|
||||
|
||||
/**
|
||||
* 终止任务
|
||||
*
|
||||
* @param bo 参数
|
||||
* @return 结果
|
||||
*/
|
||||
boolean terminationTask(FlowTerminationBo bo);
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowTask> selectByIdList(List<Long> taskIdList);
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskId 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
FlowTaskVo selectById(Long taskId);
|
||||
|
||||
/**
|
||||
* 获取下一节点信息
|
||||
*
|
||||
* @param bo 参数
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowNode> getNextNodeList(FlowNextNodeBo bo);
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList);
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskId 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
FlowHisTask selectHisTaskById(Long taskId);
|
||||
|
||||
/**
|
||||
* 按照实例id查询任务
|
||||
*
|
||||
* @param instanceIdList 流程实例id
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowTask> selectByInstIdList(List<Long> instanceIdList);
|
||||
|
||||
/**
|
||||
* 按照实例id查询任务
|
||||
*
|
||||
* @param instanceId 流程实例id
|
||||
* @return 结果
|
||||
*/
|
||||
List<FlowTask> selectByInstId(Long instanceId);
|
||||
|
||||
/**
|
||||
* 任务操作
|
||||
*
|
||||
* @param bo 参数
|
||||
* @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
|
||||
* @return 结果
|
||||
*/
|
||||
boolean taskOperation(TaskOperationBo bo, String taskOperation);
|
||||
|
||||
/**
|
||||
* 获取任务所有办理人
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList);
|
||||
|
||||
/**
|
||||
* 获取当前任务的所有办理人
|
||||
*
|
||||
* @param taskId 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
List<UserDTO> currentTaskAllUser(Long taskId);
|
||||
|
||||
/**
|
||||
* 按照节点编码查询节点
|
||||
*
|
||||
* @param nodeCode 节点编码
|
||||
* @param definitionId 流程定义id
|
||||
* @return 节点
|
||||
*/
|
||||
FlowNode getByNodeCode(String nodeCode, Long definitionId);
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.fuyuanshen.workflow.service;
|
||||
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.workflow.domain.bo.TestLeaveBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.TestLeaveVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 请假Service接口
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-07-21
|
||||
*/
|
||||
public interface ITestLeaveService {
|
||||
|
||||
/**
|
||||
* 查询请假
|
||||
*/
|
||||
TestLeaveVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询请假列表
|
||||
*/
|
||||
TableDataInfo<TestLeaveVo> queryPageList(TestLeaveBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询请假列表
|
||||
*/
|
||||
List<TestLeaveVo> queryList(TestLeaveBo bo);
|
||||
|
||||
/**
|
||||
* 新增请假
|
||||
*/
|
||||
TestLeaveVo insertByBo(TestLeaveBo bo);
|
||||
|
||||
/**
|
||||
* 修改请假
|
||||
*/
|
||||
TestLeaveVo updateByBo(TestLeaveBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除请假信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(List<Long> ids);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.translation.annotation.TranslationType;
|
||||
import com.fuyuanshen.common.translation.core.TranslationInterface;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import com.fuyuanshen.workflow.service.IFlwCategoryService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 流程分类名称翻译实现
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@TranslationType(type = FlowConstant.CATEGORY_ID_TO_NAME)
|
||||
public class CategoryNameTranslationImpl implements TranslationInterface<String> {
|
||||
|
||||
private final IFlwCategoryService flwCategoryService;
|
||||
|
||||
@Override
|
||||
public String translation(Object key, String other) {
|
||||
Long id = null;
|
||||
if (key instanceof String categoryId) {
|
||||
id = Convert.toLong(categoryId);
|
||||
} else if (key instanceof Long categoryId) {
|
||||
id = categoryId;
|
||||
}
|
||||
return flwCategoryService.selectCategoryNameById(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.common.core.constant.SystemConstants;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.core.utils.*;
|
||||
import com.fuyuanshen.common.mybatis.helper.DataBaseHelper;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import com.fuyuanshen.workflow.domain.FlowCategory;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowCategoryBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowCategoryVo;
|
||||
import com.fuyuanshen.workflow.mapper.FlwCategoryMapper;
|
||||
import com.fuyuanshen.workflow.service.IFlwCategoryService;
|
||||
import org.dromara.warm.flow.core.service.DefService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程分类Service业务层处理
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FlwCategoryServiceImpl implements IFlwCategoryService {
|
||||
|
||||
private final DefService defService;
|
||||
private final FlwCategoryMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询流程分类
|
||||
*
|
||||
* @param categoryId 主键
|
||||
* @return 流程分类
|
||||
*/
|
||||
@Override
|
||||
public FlowCategoryVo queryById(Long categoryId) {
|
||||
FlowCategoryVo category = baseMapper.selectVoById(categoryId);
|
||||
if (ObjectUtil.isNull(category)) {
|
||||
return null;
|
||||
}
|
||||
FlowCategoryVo parentCategory = baseMapper.selectVoOne(new LambdaQueryWrapper<FlowCategory>()
|
||||
.select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, category.getParentId()));
|
||||
category.setParentName(ObjectUtils.notNullGetter(parentCategory, FlowCategoryVo::getCategoryName));
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流程分类ID查询流程分类名称
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
* @return 流程分类名称
|
||||
*/
|
||||
@Cacheable(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId")
|
||||
@Override
|
||||
public String selectCategoryNameById(Long categoryId) {
|
||||
if (ObjectUtil.isNull(categoryId)) {
|
||||
return null;
|
||||
}
|
||||
FlowCategory category = baseMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
|
||||
.select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, categoryId));
|
||||
return ObjectUtils.notNullGetter(category, FlowCategory::getCategoryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的流程分类列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 流程分类列表
|
||||
*/
|
||||
@Override
|
||||
public List<FlowCategoryVo> queryList(FlowCategoryBo bo) {
|
||||
LambdaQueryWrapper<FlowCategory> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程分类树结构信息
|
||||
*
|
||||
* @param category 流程分类信息
|
||||
* @return 流程分类树信息集合
|
||||
*/
|
||||
@Override
|
||||
public List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category) {
|
||||
LambdaQueryWrapper<FlowCategory> lqw = buildQueryWrapper(category);
|
||||
List<FlowCategoryVo> categorys = baseMapper.selectVoList(lqw);
|
||||
if (CollUtil.isEmpty(categorys)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
// 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点
|
||||
List<Tree<String>> treeList = CollUtil.newArrayList();
|
||||
for (FlowCategoryVo d : categorys) {
|
||||
String parentId = d.getParentId().toString();
|
||||
FlowCategoryVo categoryVo = StreamUtils.findFirst(categorys, it -> it.getCategoryId().toString().equals(parentId));
|
||||
if (ObjectUtil.isNull(categoryVo)) {
|
||||
List<Tree<String>> trees = TreeBuildUtils.build(categorys, parentId, (dept, tree) ->
|
||||
tree.setId(dept.getCategoryId().toString())
|
||||
.setParentId(dept.getParentId().toString())
|
||||
.setName(dept.getCategoryName())
|
||||
.setWeight(dept.getOrderNum()));
|
||||
Tree<String> tree = StreamUtils.findFirst(trees, it -> it.getId().equals(d.getCategoryId().toString()));
|
||||
treeList.add(tree);
|
||||
}
|
||||
}
|
||||
return treeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验流程分类是否有数据权限
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
*/
|
||||
@Override
|
||||
public void checkCategoryDataScope(Long categoryId) {
|
||||
if (ObjectUtil.isNull(categoryId)) {
|
||||
return;
|
||||
}
|
||||
if (LoginHelper.isSuperAdmin()) {
|
||||
return;
|
||||
}
|
||||
if (baseMapper.countCategoryById(categoryId) == 0) {
|
||||
throw new ServiceException("没有权限访问流程分类数据!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验流程分类名称是否唯一
|
||||
*
|
||||
* @param category 流程分类信息
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean checkCategoryNameUnique(FlowCategoryBo category) {
|
||||
boolean exist = baseMapper.exists(new LambdaQueryWrapper<FlowCategory>()
|
||||
.eq(FlowCategory::getCategoryName, category.getCategoryName())
|
||||
.eq(FlowCategory::getParentId, category.getParentId())
|
||||
.ne(ObjectUtil.isNotNull(category.getCategoryId()), FlowCategory::getCategoryId, category.getCategoryId()));
|
||||
return !exist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程分类是否存在流程定义
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
* @return 结果 true 存在 false 不存在
|
||||
*/
|
||||
@Override
|
||||
public boolean checkCategoryExistDefinition(Long categoryId) {
|
||||
FlowDefinition definition = new FlowDefinition();
|
||||
definition.setCategory(categoryId.toString());
|
||||
return defService.exists(definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在流程分类子节点
|
||||
*
|
||||
* @param categoryId 流程分类ID
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean hasChildByCategoryId(Long categoryId) {
|
||||
return baseMapper.exists(new LambdaQueryWrapper<FlowCategory>()
|
||||
.eq(FlowCategory::getParentId, categoryId));
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<FlowCategory> buildQueryWrapper(FlowCategoryBo bo) {
|
||||
LambdaQueryWrapper<FlowCategory> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(FlowCategory::getDelFlag, SystemConstants.NORMAL);
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getCategoryId()), FlowCategory::getCategoryId, bo.getCategoryId());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), FlowCategory::getParentId, bo.getParentId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), FlowCategory::getCategoryName, bo.getCategoryName());
|
||||
lqw.orderByAsc(FlowCategory::getAncestors);
|
||||
lqw.orderByAsc(FlowCategory::getParentId);
|
||||
lqw.orderByAsc(FlowCategory::getOrderNum);
|
||||
lqw.orderByAsc(FlowCategory::getCategoryId);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程分类
|
||||
*
|
||||
* @param bo 流程分类
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public int insertByBo(FlowCategoryBo bo) {
|
||||
FlowCategory info = baseMapper.selectById(bo.getParentId());
|
||||
FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
|
||||
category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId());
|
||||
return baseMapper.insert(category);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改流程分类
|
||||
*
|
||||
* @param bo 流程分类
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId")
|
||||
@Override
|
||||
public int updateByBo(FlowCategoryBo bo) {
|
||||
FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
|
||||
FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId());
|
||||
if (ObjectUtil.isNull(oldCategory)) {
|
||||
throw new ServiceException("流程分类不存在,无法修改");
|
||||
}
|
||||
if (!oldCategory.getParentId().equals(category.getParentId())) {
|
||||
// 如果是新父流程分类 则校验是否具有新父流程分类权限 避免越权
|
||||
this.checkCategoryDataScope(category.getParentId());
|
||||
FlowCategory newParentCategory = baseMapper.selectById(category.getParentId());
|
||||
if (ObjectUtil.isNotNull(newParentCategory)) {
|
||||
String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId();
|
||||
String oldAncestors = oldCategory.getAncestors();
|
||||
category.setAncestors(newAncestors);
|
||||
updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors);
|
||||
}
|
||||
} else {
|
||||
category.setAncestors(oldCategory.getAncestors());
|
||||
}
|
||||
return baseMapper.updateById(category);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改子元素关系
|
||||
*
|
||||
* @param categoryId 被修改的流程分类ID
|
||||
* @param newAncestors 新的父ID集合
|
||||
* @param oldAncestors 旧的父ID集合
|
||||
*/
|
||||
private void updateCategoryChildren(Long categoryId, String newAncestors, String oldAncestors) {
|
||||
List<FlowCategory> children = baseMapper.selectList(new LambdaQueryWrapper<FlowCategory>()
|
||||
.apply(DataBaseHelper.findInSet(categoryId, "ancestors")));
|
||||
List<FlowCategory> list = new ArrayList<>();
|
||||
for (FlowCategory child : children) {
|
||||
FlowCategory category = new FlowCategory();
|
||||
category.setCategoryId(child.getCategoryId());
|
||||
category.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
|
||||
list.add(category);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
baseMapper.updateBatchById(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程分类信息
|
||||
*
|
||||
* @param categoryId 主键
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId")
|
||||
@Override
|
||||
public int deleteWithValidById(Long categoryId) {
|
||||
return baseMapper.deleteById(categoryId);
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.domain.dto.UserDTO;
|
||||
import com.fuyuanshen.common.core.utils.SpringUtils;
|
||||
import com.fuyuanshen.common.core.utils.StreamUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mail.utils.MailUtils;
|
||||
import com.fuyuanshen.common.sse.dto.SseMessageDto;
|
||||
import com.fuyuanshen.common.sse.utils.SseMessageUtils;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.enums.MessageTypeEnum;
|
||||
import com.fuyuanshen.workflow.service.IFlwCommonService;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskAssigneeService;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskService;
|
||||
import org.dromara.warm.flow.core.entity.Node;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.core.enums.SkipType;
|
||||
import org.dromara.warm.flow.core.service.NodeService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* 工作流工具
|
||||
*
|
||||
* @author LionLi
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FlwCommonServiceImpl implements IFlwCommonService {
|
||||
private final NodeService nodeService;
|
||||
|
||||
/**
|
||||
* 构建工作流用户
|
||||
*
|
||||
* @param permissionList 办理用户
|
||||
* @return 用户
|
||||
*/
|
||||
@Override
|
||||
public List<String> buildUser(List<String> permissionList) {
|
||||
if (CollUtil.isEmpty(permissionList)) {
|
||||
return List.of();
|
||||
}
|
||||
IFlwTaskAssigneeService taskAssigneeService = SpringUtils.getBean(IFlwTaskAssigneeService.class);
|
||||
String processedBys = CollUtil.join(permissionList, StringUtils.SEPARATOR);
|
||||
// 根据 processedBy 前缀判断处理人类型,分别获取用户列表
|
||||
List<UserDTO> users = taskAssigneeService.fetchUsersByStorageIds(processedBys);
|
||||
|
||||
return StreamUtils.toList(users, userDTO -> String.valueOf(userDTO.getUserId()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param flowName 流程定义名称
|
||||
* @param messageType 消息类型
|
||||
* @param message 消息内容,为空则发送默认配置的消息内容
|
||||
*/
|
||||
@Override
|
||||
public void sendMessage(String flowName, Long instId, List<String> messageType, String message) {
|
||||
IFlwTaskService flwTaskService = SpringUtils.getBean(IFlwTaskService.class);
|
||||
List<UserDTO> userList = new ArrayList<>();
|
||||
List<FlowTask> list = flwTaskService.selectByInstId(instId);
|
||||
if (StringUtils.isBlank(message)) {
|
||||
message = "有新的【" + flowName + "】单据已经提交至您,请您及时处理。";
|
||||
}
|
||||
for (Task task : list) {
|
||||
List<UserDTO> users = flwTaskService.currentTaskAllUser(task.getId());
|
||||
if (CollUtil.isNotEmpty(users)) {
|
||||
userList.addAll(users);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(userList)) {
|
||||
for (String code : messageType) {
|
||||
MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
|
||||
if (ObjectUtil.isNotEmpty(messageTypeEnum)) {
|
||||
switch (messageTypeEnum) {
|
||||
case SYSTEM_MESSAGE:
|
||||
SseMessageDto dto = new SseMessageDto();
|
||||
dto.setUserIds(StreamUtils.toList(userList, UserDTO::getUserId).stream().distinct().collect(Collectors.toList()));
|
||||
dto.setMessage(message);
|
||||
SseMessageUtils.publishMessage(dto);
|
||||
break;
|
||||
case EMAIL_MESSAGE:
|
||||
MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), "单据审批提醒", message);
|
||||
break;
|
||||
case SMS_MESSAGE:
|
||||
//todo 短信发送
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected value: " + messageTypeEnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 申请人节点编码
|
||||
*
|
||||
* @param definitionId 流程定义id
|
||||
* @return 申请人节点编码
|
||||
*/
|
||||
@Override
|
||||
public String applyNodeCode(Long definitionId) {
|
||||
Node startNode = nodeService.getStartNode(definitionId);
|
||||
Node nextNode = nodeService.getNextNode(definitionId, startNode.getNodeCode(), null, SkipType.PASS.getKey());
|
||||
return nextNode.getNodeCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,272 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.core.utils.StreamUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import com.fuyuanshen.workflow.domain.FlowCategory;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowDefinitionVo;
|
||||
import com.fuyuanshen.workflow.mapper.FlwCategoryMapper;
|
||||
import com.fuyuanshen.workflow.service.IFlwCommonService;
|
||||
import com.fuyuanshen.workflow.service.IFlwDefinitionService;
|
||||
import org.dromara.warm.flow.core.dto.DefJson;
|
||||
import org.dromara.warm.flow.core.enums.NodeType;
|
||||
import org.dromara.warm.flow.core.enums.PublishStatus;
|
||||
import org.dromara.warm.flow.core.service.DefService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
||||
import org.dromara.warm.flow.orm.entity.FlowHisTask;
|
||||
import org.dromara.warm.flow.orm.entity.FlowNode;
|
||||
import org.dromara.warm.flow.orm.entity.FlowSkip;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowSkipMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.fuyuanshen.common.core.constant.TenantConstants.DEFAULT_TENANT_ID;
|
||||
|
||||
/**
|
||||
* 流程定义 服务层实现
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
||||
|
||||
private final DefService defService;
|
||||
private final FlowDefinitionMapper flowDefinitionMapper;
|
||||
private final FlowHisTaskMapper flowHisTaskMapper;
|
||||
private final FlowNodeMapper flowNodeMapper;
|
||||
private final FlowSkipMapper flowSkipMapper;
|
||||
private final FlwCategoryMapper flwCategoryMapper;
|
||||
private final IFlwCommonService flwCommonService;
|
||||
|
||||
/**
|
||||
* 查询流程定义列表
|
||||
*
|
||||
* @param flowDefinition 流程定义信息
|
||||
* @param pageQuery 分页
|
||||
* @return 返回分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowDefinitionVo> queryList(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition);
|
||||
wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey());
|
||||
Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
|
||||
TableDataInfo<FlowDefinitionVo> build = TableDataInfo.build();
|
||||
build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class));
|
||||
build.setTotal(page.getTotal());
|
||||
return build;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未发布的流程定义列表
|
||||
*
|
||||
* @param flowDefinition 流程定义信息
|
||||
* @param pageQuery 分页
|
||||
* @return 返回分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition);
|
||||
wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey()));
|
||||
Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
|
||||
TableDataInfo<FlowDefinitionVo> build = TableDataInfo.build();
|
||||
build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class));
|
||||
build.setTotal(page.getTotal());
|
||||
return build;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<FlowDefinition> buildQueryWrapper(FlowDefinition flowDefinition) {
|
||||
LambdaQueryWrapper<FlowDefinition> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowCode()), FlowDefinition::getFlowCode, flowDefinition.getFlowCode());
|
||||
wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowName()), FlowDefinition::getFlowName, flowDefinition.getFlowName());
|
||||
if (StringUtils.isNotBlank(flowDefinition.getCategory())) {
|
||||
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinition.getCategory()));
|
||||
wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr));
|
||||
}
|
||||
wrapper.orderByDesc(FlowDefinition::getCreateTime);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean publish(Long id) {
|
||||
List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, id));
|
||||
List<String> errorMsg = new ArrayList<>();
|
||||
if (CollUtil.isNotEmpty(flowNodes)) {
|
||||
for (FlowNode flowNode : flowNodes) {
|
||||
String applyNodeCode = flwCommonService.applyNodeCode(id);
|
||||
if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) {
|
||||
errorMsg.add(flowNode.getNodeName());
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(errorMsg)) {
|
||||
throw new ServiceException("节点【" + StringUtils.join(errorMsg, ",") + "】未配置办理人!");
|
||||
}
|
||||
}
|
||||
return defService.publish(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入流程定义
|
||||
*
|
||||
* @param file 文件
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean importJson(MultipartFile file, String category) {
|
||||
try {
|
||||
DefJson defJson = JsonUtils.parseObject(file.getBytes(), DefJson.class);
|
||||
defJson.setCategory(category);
|
||||
defService.importDef(defJson);
|
||||
} catch (IOException e) {
|
||||
log.error("读取文件流错误: {}", e.getMessage(), e);
|
||||
throw new IllegalStateException("文件读取失败,请检查文件内容", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出流程定义
|
||||
*
|
||||
* @param id 流程定义id
|
||||
* @param response 响应
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
@Override
|
||||
public void exportDef(Long id, HttpServletResponse response) throws IOException {
|
||||
byte[] data = defService.exportJson(id).getBytes(StandardCharsets.UTF_8);
|
||||
// 设置响应头和内容类型
|
||||
response.reset();
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
response.setContentType("application/text");
|
||||
response.setHeader("Content-Disposition", "attachment;");
|
||||
response.addHeader("Content-Length", "" + data.length);
|
||||
IoUtil.write(response.getOutputStream(), false, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程定义
|
||||
*
|
||||
* @param ids 流程定义id
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean removeDef(List<Long> ids) {
|
||||
LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.in(FlowHisTask::getDefinitionId, ids);
|
||||
List<FlowHisTask> flowHisTasks = flowHisTaskMapper.selectList(wrapper);
|
||||
if (CollUtil.isNotEmpty(flowHisTasks)) {
|
||||
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId));
|
||||
if (CollUtil.isNotEmpty(flowDefinitions)) {
|
||||
String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode);
|
||||
log.info("流程定义【{}】已被使用不可被删除!", join);
|
||||
throw new ServiceException("流程定义【" + join + "】已被使用不可被删除!");
|
||||
}
|
||||
}
|
||||
try {
|
||||
defService.removeDef(ids);
|
||||
} catch (Exception e) {
|
||||
log.error("Error removing flow definitions: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("Failed to remove flow definitions", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增租户流程定义
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void syncDef(String tenantId) {
|
||||
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID));
|
||||
if (CollUtil.isEmpty(flowDefinitions)) {
|
||||
return;
|
||||
}
|
||||
FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
|
||||
.eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
|
||||
flowCategory.setCategoryId(null);
|
||||
flowCategory.setTenantId(tenantId);
|
||||
flowCategory.setCreateDept(null);
|
||||
flowCategory.setCreateBy(null);
|
||||
flowCategory.setCreateTime(null);
|
||||
flowCategory.setUpdateBy(null);
|
||||
flowCategory.setUpdateTime(null);
|
||||
flwCategoryMapper.insert(flowCategory);
|
||||
List<Long> defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId);
|
||||
List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().in(FlowNode::getDefinitionId, defIds));
|
||||
List<FlowSkip> flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper<FlowSkip>().in(FlowSkip::getDefinitionId, defIds));
|
||||
for (FlowDefinition definition : flowDefinitions) {
|
||||
FlowDefinition flowDefinition = BeanUtil.toBean(definition, FlowDefinition.class);
|
||||
flowDefinition.setId(null);
|
||||
flowDefinition.setTenantId(tenantId);
|
||||
flowDefinition.setIsPublish(0);
|
||||
flowDefinition.setCategory(String.valueOf(flowCategory.getCategoryId()));
|
||||
int insert = flowDefinitionMapper.insert(flowDefinition);
|
||||
if (insert <= 0) {
|
||||
log.info("同步流程定义【{}】失败!", definition.getFlowCode());
|
||||
continue;
|
||||
}
|
||||
log.info("同步流程定义【{}】成功!", definition.getFlowCode());
|
||||
Long definitionId = flowDefinition.getId();
|
||||
if (CollUtil.isNotEmpty(flowNodes)) {
|
||||
List<FlowNode> nodes = StreamUtils.filter(flowNodes, node -> node.getDefinitionId().equals(definition.getId()));
|
||||
if (CollUtil.isNotEmpty(nodes)) {
|
||||
List<FlowNode> flowNodeList = BeanUtil.copyToList(nodes, FlowNode.class);
|
||||
flowNodeList.forEach(e -> {
|
||||
e.setId(null);
|
||||
e.setDefinitionId(definitionId);
|
||||
e.setTenantId(tenantId);
|
||||
e.setPermissionFlag(null);
|
||||
});
|
||||
flowNodeMapper.insertOrUpdate(flowNodeList);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(flowSkips)) {
|
||||
List<FlowSkip> skips = StreamUtils.filter(flowSkips, skip -> skip.getDefinitionId().equals(definition.getId()));
|
||||
if (CollUtil.isNotEmpty(skips)) {
|
||||
List<FlowSkip> flowSkipList = BeanUtil.copyToList(skips, FlowSkip.class);
|
||||
flowSkipList.forEach(e -> {
|
||||
e.setId(null);
|
||||
e.setDefinitionId(definitionId);
|
||||
e.setTenantId(tenantId);
|
||||
});
|
||||
flowSkipMapper.insertOrUpdate(flowSkipList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,430 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.domain.dto.UserDTO;
|
||||
import com.fuyuanshen.common.core.enums.BusinessStatusEnum;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.core.utils.StreamUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.enums.TaskStatusEnum;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowCancelBo;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowInstanceBo;
|
||||
import com.fuyuanshen.workflow.domain.bo.FlowInvalidBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowHisTaskVo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowInstanceVo;
|
||||
import com.fuyuanshen.workflow.handler.FlowProcessEventHandler;
|
||||
import com.fuyuanshen.workflow.mapper.FlwCategoryMapper;
|
||||
import com.fuyuanshen.workflow.mapper.FlwInstanceMapper;
|
||||
import com.fuyuanshen.workflow.service.IFlwInstanceService;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskService;
|
||||
import org.dromara.warm.flow.core.constant.ExceptionCons;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.entity.Definition;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.core.enums.NodeType;
|
||||
import org.dromara.warm.flow.core.service.DefService;
|
||||
import org.dromara.warm.flow.core.service.InsService;
|
||||
import org.dromara.warm.flow.core.service.TaskService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowHisTask;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 流程实例 服务层实现
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
|
||||
private final InsService insService;
|
||||
private final DefService defService;
|
||||
private final TaskService taskService;
|
||||
private final FlowHisTaskMapper flowHisTaskMapper;
|
||||
private final FlowInstanceMapper flowInstanceMapper;
|
||||
private final FlowProcessEventHandler flowProcessEventHandler;
|
||||
private final IFlwTaskService flwTaskService;
|
||||
private final FlwInstanceMapper flwInstanceMapper;
|
||||
private final FlwCategoryMapper flwCategoryMapper;
|
||||
|
||||
/**
|
||||
* 分页查询正在运行的流程实例
|
||||
*
|
||||
* @param flowInstanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowInstanceVo> selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(flowInstanceBo);
|
||||
queryWrapper.in("fi.flow_status", BusinessStatusEnum.runningStatus());
|
||||
Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询已结束的流程实例
|
||||
*
|
||||
* @param flowInstanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowInstanceVo> selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(flowInstanceBo);
|
||||
queryWrapper.in("fi.flow_status", BusinessStatusEnum.finishStatus());
|
||||
Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据业务id查询流程实例详细信息
|
||||
*
|
||||
* @param businessId 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public FlowInstanceVo queryByBusinessId(Long businessId) {
|
||||
FlowInstance instance = this.selectInstByBusinessId(String.valueOf(businessId));
|
||||
FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class);
|
||||
Definition definition = defService.getById(instanceVo.getDefinitionId());
|
||||
instanceVo.setFlowName(definition.getFlowName());
|
||||
instanceVo.setFlowCode(definition.getFlowCode());
|
||||
instanceVo.setVersion(definition.getVersion());
|
||||
instanceVo.setFormCustom(definition.getFormCustom());
|
||||
instanceVo.setFormPath(definition.getFormPath());
|
||||
instanceVo.setCategory(definition.getCategory());
|
||||
return instanceVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用查询条件
|
||||
*
|
||||
* @param flowInstanceBo 查询条件
|
||||
* @return 查询条件构造方法
|
||||
*/
|
||||
private QueryWrapper<FlowInstanceBo> buildQueryWrapper(FlowInstanceBo flowInstanceBo) {
|
||||
QueryWrapper<FlowInstanceBo> queryWrapper = Wrappers.query();
|
||||
queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getNodeName()), "fi.node_name", flowInstanceBo.getNodeName());
|
||||
queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowName()), "fd.flow_name", flowInstanceBo.getFlowName());
|
||||
queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowCode()), "fd.flow_code", flowInstanceBo.getFlowCode());
|
||||
if (StringUtils.isNotBlank(flowInstanceBo.getCategory())) {
|
||||
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowInstanceBo.getCategory()));
|
||||
queryWrapper.in("fd.category", StreamUtils.toList(categoryIds, Convert::toStr));
|
||||
}
|
||||
queryWrapper.eq(StringUtils.isNotBlank(flowInstanceBo.getBusinessId()), "fi.business_id", flowInstanceBo.getBusinessId());
|
||||
queryWrapper.in(CollUtil.isNotEmpty(flowInstanceBo.getCreateByIds()), "fi.create_by", flowInstanceBo.getCreateByIds());
|
||||
queryWrapper.eq("fi.del_flag", "0");
|
||||
queryWrapper.orderByDesc("fi.create_time");
|
||||
return queryWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据业务id查询流程实例
|
||||
*
|
||||
* @param businessId 业务id
|
||||
*/
|
||||
@Override
|
||||
public FlowInstance selectInstByBusinessId(String businessId) {
|
||||
return flowInstanceMapper.selectOne(new LambdaQueryWrapper<FlowInstance>().eq(FlowInstance::getBusinessId, businessId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照实例id查询流程实例
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
*/
|
||||
@Override
|
||||
public FlowInstance selectInstById(Long instanceId) {
|
||||
return flowInstanceMapper.selectById(instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照实例id查询流程实例
|
||||
*
|
||||
* @param instanceIds 实例id
|
||||
*/
|
||||
@Override
|
||||
public List<FlowInstance> selectInstListByIdList(List<Long> instanceIds) {
|
||||
return flowInstanceMapper.selectByIds(instanceIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照业务id删除流程实例
|
||||
*
|
||||
* @param businessIds 业务id
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteByBusinessIds(List<Long> businessIds) {
|
||||
List<FlowInstance> flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper<FlowInstance>().in(FlowInstance::getBusinessId, StreamUtils.toList(businessIds, Convert::toStr)));
|
||||
if (CollUtil.isEmpty(flowInstances)) {
|
||||
log.warn("未找到对应的流程实例信息,无法执行删除操作。");
|
||||
return false;
|
||||
}
|
||||
return insService.remove(StreamUtils.toList(flowInstances, FlowInstance::getId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照实例id删除流程实例
|
||||
*
|
||||
* @param instanceIds 实例id
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteByInstanceIds(List<Long> instanceIds) {
|
||||
// 获取实例信息
|
||||
List<Instance> instances = insService.getByIds(instanceIds);
|
||||
if (CollUtil.isEmpty(instances)) {
|
||||
log.warn("未找到对应的流程实例信息,无法执行删除操作。");
|
||||
return false;
|
||||
}
|
||||
// 获取定义信息
|
||||
Map<Long, Definition> definitionMap = defService.getByIds(
|
||||
StreamUtils.toList(instances, Instance::getDefinitionId)
|
||||
).stream().collect(Collectors.toMap(Definition::getId, definition -> definition));
|
||||
|
||||
// 逐一触发删除事件
|
||||
instances.forEach(instance -> {
|
||||
Definition definition = definitionMap.get(instance.getDefinitionId());
|
||||
if (ObjectUtil.isNull(definition)) {
|
||||
log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
|
||||
return;
|
||||
}
|
||||
flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
|
||||
});
|
||||
|
||||
// 删除实例
|
||||
return insService.remove(instanceIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销流程
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean cancelProcessApply(FlowCancelBo bo) {
|
||||
try {
|
||||
Instance instance = selectInstByBusinessId(bo.getBusinessId());
|
||||
if (instance == null) {
|
||||
throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
|
||||
}
|
||||
Definition definition = defService.getById(instance.getDefinitionId());
|
||||
if (definition == null) {
|
||||
throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF);
|
||||
}
|
||||
String message = bo.getMessage();
|
||||
String userIdStr = LoginHelper.getUserIdStr();
|
||||
BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus());
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.message(message)
|
||||
.flowStatus(BusinessStatusEnum.CANCEL.getStatus())
|
||||
.hisStatus(BusinessStatusEnum.CANCEL.getStatus())
|
||||
.handler(userIdStr)
|
||||
.ignore(true);
|
||||
taskService.revoke(instance.getId(), flowParams);
|
||||
} catch (Exception e) {
|
||||
log.error("撤销失败: {}", e.getMessage(), e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登陆人发起的流程实例
|
||||
*
|
||||
* @param instanceBo 流程实例
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(instanceBo);
|
||||
queryWrapper.eq("fi.create_by", LoginHelper.getUserIdStr());
|
||||
Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程图,流程记录
|
||||
*
|
||||
* @param businessId 业务id
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> flowHisTaskList(String businessId) {
|
||||
FlowInstance flowInstance = this.selectInstByBusinessId(businessId);
|
||||
if (ObjectUtil.isNull(flowInstance)) {
|
||||
throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
|
||||
}
|
||||
Long instanceId = flowInstance.getId();
|
||||
//运行中的任务
|
||||
List<FlowHisTaskVo> list = new ArrayList<>();
|
||||
List<FlowTask> flowTaskList = flwTaskService.selectByInstId(instanceId);
|
||||
if (CollUtil.isNotEmpty(flowTaskList)) {
|
||||
List<FlowHisTaskVo> flowHisTaskVos = BeanUtil.copyToList(flowTaskList, FlowHisTaskVo.class);
|
||||
for (FlowHisTaskVo flowHisTaskVo : flowHisTaskVos) {
|
||||
flowHisTaskVo.setFlowStatus(TaskStatusEnum.WAITING.getStatus());
|
||||
flowHisTaskVo.setUpdateTime(null);
|
||||
flowHisTaskVo.setRunDuration(null);
|
||||
List<UserDTO> allUser = flwTaskService.currentTaskAllUser(flowHisTaskVo.getId());
|
||||
if (CollUtil.isNotEmpty(allUser)) {
|
||||
String join = StreamUtils.join(allUser, e -> String.valueOf(e.getUserId()));
|
||||
flowHisTaskVo.setApprover(join);
|
||||
}
|
||||
if (BusinessStatusEnum.isDraftOrCancelOrBack(flowInstance.getFlowStatus())) {
|
||||
flowHisTaskVo.setApprover(LoginHelper.getUserIdStr());
|
||||
flowHisTaskVo.setApproveName(LoginHelper.getLoginUser().getNickname());
|
||||
}
|
||||
}
|
||||
list.addAll(flowHisTaskVos);
|
||||
}
|
||||
//历史任务
|
||||
LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(FlowHisTask::getInstanceId, instanceId);
|
||||
wrapper.eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey());
|
||||
wrapper.orderByDesc(FlowHisTask::getCreateTime).orderByDesc(FlowHisTask::getUpdateTime);
|
||||
List<FlowHisTask> flowHisTasks = flowHisTaskMapper.selectList(wrapper);
|
||||
if (CollUtil.isNotEmpty(flowHisTasks)) {
|
||||
list.addAll(BeanUtil.copyToList(flowHisTasks, FlowHisTaskVo.class));
|
||||
}
|
||||
return Map.of("list", list,"instanceId",instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照实例id更新状态
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
* @param status 状态
|
||||
*/
|
||||
@Override
|
||||
public void updateStatus(Long instanceId, String status) {
|
||||
LambdaUpdateWrapper<FlowInstance> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.set(FlowInstance::getFlowStatus, status);
|
||||
wrapper.eq(FlowInstance::getId, instanceId);
|
||||
flowInstanceMapper.update(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程变量
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> instanceVariable(Long instanceId) {
|
||||
FlowInstance flowInstance = flowInstanceMapper.selectById(instanceId);
|
||||
Map<String, Object> variableMap = Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap());
|
||||
List<Map<String, Object>> variableList = variableMap.entrySet().stream()
|
||||
.map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue()))
|
||||
.toList();
|
||||
return Map.of("variableList", variableList, "variable", flowInstance.getVariable());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置流程变量
|
||||
*
|
||||
* @param instanceId 实例id
|
||||
* @param variable 流程变量
|
||||
*/
|
||||
@Override
|
||||
public void setVariable(Long instanceId, Map<String, Object> variable) {
|
||||
Instance instance = insService.getById(instanceId);
|
||||
if (instance != null) {
|
||||
taskService.mergeVariable(instance, variable);
|
||||
insService.updateById(instance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按任务id查询实例
|
||||
*
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
@Override
|
||||
public FlowInstance selectByTaskId(Long taskId) {
|
||||
Task task = taskService.getById(taskId);
|
||||
if (task == null) {
|
||||
FlowHisTask flowHisTask = flwTaskService.selectHisTaskById(taskId);
|
||||
if (flowHisTask != null) {
|
||||
return this.selectInstById(flowHisTask.getInstanceId());
|
||||
}
|
||||
} else {
|
||||
return this.selectInstById(task.getInstanceId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按任务id查询实例
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
*/
|
||||
@Override
|
||||
public List<FlowInstance> selectByTaskIdList(List<Long> taskIdList) {
|
||||
if (CollUtil.isEmpty(taskIdList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Set<Long> instanceIds = new HashSet<>();
|
||||
List<FlowTask> flowTaskList = flwTaskService.selectByIdList(taskIdList);
|
||||
for (FlowTask flowTask : flowTaskList) {
|
||||
instanceIds.add(flowTask.getInstanceId());
|
||||
}
|
||||
List<FlowHisTask> flowHisTaskList = flwTaskService.selectHisTaskByIdList(taskIdList);
|
||||
for (FlowHisTask flowHisTask : flowHisTaskList) {
|
||||
instanceIds.add(flowHisTask.getInstanceId());
|
||||
}
|
||||
if (!instanceIds.isEmpty()) {
|
||||
return this.selectInstListByIdList(new ArrayList<>(instanceIds));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 作废流程
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean processInvalid(FlowInvalidBo bo) {
|
||||
try {
|
||||
Instance instance = insService.getById(bo.getId());
|
||||
if (instance != null) {
|
||||
BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
|
||||
}
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.message(bo.getComment())
|
||||
.flowStatus(BusinessStatusEnum.INVALID.getStatus())
|
||||
.hisStatus(TaskStatusEnum.INVALID.getStatus())
|
||||
.ignore(true);
|
||||
taskService.terminationByInsId(bo.getId(), flowParams);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,243 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.domain.dto.DictTypeDTO;
|
||||
import com.fuyuanshen.common.core.service.DictService;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
import org.dromara.warm.flow.ui.service.NodeExtService;
|
||||
import org.dromara.warm.flow.ui.vo.NodeExt;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.enums.ButtonPermissionEnum;
|
||||
import com.fuyuanshen.workflow.common.enums.NodeExtEnum;
|
||||
import com.fuyuanshen.workflow.domain.vo.ButtonPermissionVo;
|
||||
import com.fuyuanshen.workflow.service.IFlwNodeExtService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 流程设计器-节点扩展属性
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService {
|
||||
|
||||
/**
|
||||
* 存储不同 dictType 对应的配置信息
|
||||
*/
|
||||
private static final Map<String, ButtonPermission> CHILD_NODE_MAP = new HashMap<>();
|
||||
|
||||
record ButtonPermission(String label, Integer type, Boolean must, Boolean multiple) {
|
||||
}
|
||||
|
||||
static {
|
||||
CHILD_NODE_MAP.put(ButtonPermissionEnum.class.getSimpleName(),
|
||||
new ButtonPermission("权限按钮", 4, false, true));
|
||||
}
|
||||
|
||||
private final DictService dictService;
|
||||
|
||||
/**
|
||||
* 获取节点扩展属性
|
||||
*
|
||||
* @return 节点扩展属性列表
|
||||
*/
|
||||
@Override
|
||||
public List<NodeExt> getNodeExt() {
|
||||
List<NodeExt> nodeExtList = new ArrayList<>();
|
||||
// 构建按钮权限页面
|
||||
nodeExtList.add(buildNodeExt("wf_button_tab", "权限", 2,
|
||||
List.of(ButtonPermissionEnum.class)));
|
||||
// 自定义构建 规则参考 NodeExt 与 warm-flow文档说明
|
||||
// nodeExtList.add(buildNodeExt("xxx_xxx", "xxx", 1, List);
|
||||
return nodeExtList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建一个 `NodeExt` 对象
|
||||
*
|
||||
* @param code 唯一编码
|
||||
* @param name 名称(新页签时,作为页签名称)
|
||||
* @param type 节点类型(1: 基础设置,2: 新页签)
|
||||
* @param sources 数据来源(枚举类或字典类型)
|
||||
* @return 构建的 `NodeExt` 对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked cast")
|
||||
private NodeExt buildNodeExt(String code, String name, int type, List<Object> sources) {
|
||||
NodeExt nodeExt = new NodeExt();
|
||||
nodeExt.setCode(code);
|
||||
nodeExt.setType(type);
|
||||
nodeExt.setName(name);
|
||||
nodeExt.setChilds(sources.stream()
|
||||
.map(source -> {
|
||||
if (source instanceof Class<?> clazz && NodeExtEnum.class.isAssignableFrom(clazz)) {
|
||||
return buildChildNode((Class<? extends NodeExtEnum>) clazz);
|
||||
} else if (source instanceof String dictType) {
|
||||
return buildChildNode(dictType);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(ObjectUtil::isNotNull)
|
||||
.toList()
|
||||
);
|
||||
return nodeExt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据枚举类型构建一个 `ChildNode` 对象
|
||||
*
|
||||
* @param enumClass 枚举类,必须实现 `NodeExtEnum` 接口
|
||||
* @return 构建的 `ChildNode` 对象
|
||||
*/
|
||||
private NodeExt.ChildNode buildChildNode(Class<? extends NodeExtEnum> enumClass) {
|
||||
if (!enumClass.isEnum()) {
|
||||
return null;
|
||||
}
|
||||
String simpleName = enumClass.getSimpleName();
|
||||
NodeExt.ChildNode childNode = buildChildNodeMap(simpleName);
|
||||
// 编码,此json中唯
|
||||
childNode.setCode(simpleName);
|
||||
// 字典,下拉框和复选框时用到
|
||||
childNode.setDict(Arrays.stream(enumClass.getEnumConstants())
|
||||
.map(NodeExtEnum.class::cast)
|
||||
.map(x ->
|
||||
new NodeExt.DictItem(x.getLabel(), x.getValue(), x.isSelected())
|
||||
).toList());
|
||||
return childNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型构建 `ChildNode` 对象
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @return 构建的 `ChildNode` 对象
|
||||
*/
|
||||
private NodeExt.ChildNode buildChildNode(String dictType) {
|
||||
DictTypeDTO dictTypeDTO = dictService.getDictType(dictType);
|
||||
if (ObjectUtil.isNull(dictTypeDTO)) {
|
||||
return null;
|
||||
}
|
||||
NodeExt.ChildNode childNode = buildChildNodeMap(dictType);
|
||||
// 编码,此json中唯一
|
||||
childNode.setCode(dictType);
|
||||
// label名称
|
||||
childNode.setLabel(dictTypeDTO.getDictName());
|
||||
// 描述
|
||||
childNode.setDesc(dictTypeDTO.getRemark());
|
||||
// 字典,下拉框和复选框时用到
|
||||
childNode.setDict(dictService.getDictData(dictType)
|
||||
.stream().map(x ->
|
||||
new NodeExt.DictItem(x.getDictLabel(), x.getDictValue(), Convert.toBool(x.getIsDefault(), false))
|
||||
).toList());
|
||||
return childNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 CHILD_NODE_MAP 中的配置信息,构建一个基本的 ChildNode 对象
|
||||
* 该方法用于设置 ChildNode 的常规属性,例如 label、type、是否必填、是否多选等
|
||||
*
|
||||
* @param key CHILD_NODE_MAP 的 key
|
||||
* @return 返回构建好的 ChildNode 对象
|
||||
*/
|
||||
private NodeExt.ChildNode buildChildNodeMap(String key) {
|
||||
NodeExt.ChildNode childNode = new NodeExt.ChildNode();
|
||||
ButtonPermission bp = CHILD_NODE_MAP.get(key);
|
||||
if (bp == null) {
|
||||
childNode.setType(1);
|
||||
childNode.setMust(false);
|
||||
childNode.setMultiple(true);
|
||||
return childNode;
|
||||
}
|
||||
// label名称
|
||||
childNode.setLabel(bp.label());
|
||||
// 1:输入框 2:输入框 3:下拉框 4:选择框
|
||||
childNode.setType(bp.type());
|
||||
// 是否必填
|
||||
childNode.setMust(bp.must());
|
||||
// 是否多选
|
||||
childNode.setMultiple(bp.multiple());
|
||||
return childNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
|
||||
*
|
||||
* @param ext 扩展属性 JSON 字符串
|
||||
* @return 按钮权限 VO 列表
|
||||
*/
|
||||
@Override
|
||||
public List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext) {
|
||||
// 解析 ext 为 Map<code, Set<value>>,用于标记权限
|
||||
Map<String, Set<String>> permissionMap = JsonUtils.parseArray(ext, ButtonPermissionVo.class)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
ButtonPermissionVo::getCode,
|
||||
item -> StringUtils.splitList(item.getValue()).stream()
|
||||
.map(String::trim)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet()),
|
||||
(a, b) -> b,
|
||||
HashMap::new
|
||||
));
|
||||
|
||||
// 构建按钮权限列表,标记哪些按钮在 permissionMap 中出现(表示已勾选)
|
||||
return buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将权限映射与按钮权限来源(枚举类或字典类型)进行匹配,生成权限视图列表
|
||||
* <p>
|
||||
* 使用说明:
|
||||
* - sources 支持传入多个来源类型,支持 NodeExtEnum 枚举类 或 字典类型字符串(dictType)
|
||||
* - 若需要扩展更多按钮权限,只需在 sources 中新增对应的枚举类或字典类型
|
||||
* <p>
|
||||
* 示例:
|
||||
* buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class, "custom_button_dict"));
|
||||
*
|
||||
* @param permissionMap 权限映射
|
||||
* @param sources 枚举类或字典类型列表
|
||||
* @return 按钮权限视图对象列表
|
||||
*/
|
||||
@SuppressWarnings("unchecked cast")
|
||||
private List<ButtonPermissionVo> buildPermissionsFromSources(Map<String, Set<String>> permissionMap, List<Object> sources) {
|
||||
return sources.stream()
|
||||
.flatMap(source -> {
|
||||
if (source instanceof Class<?> clazz && NodeExtEnum.class.isAssignableFrom(clazz)) {
|
||||
Set<String> selectedSet = permissionMap.getOrDefault(clazz.getSimpleName(), Collections.emptySet());
|
||||
return extractDictItems(this.buildChildNode((Class<? extends NodeExtEnum>) clazz), selectedSet).stream();
|
||||
} else if (source instanceof String dictType) {
|
||||
Set<String> selectedSet = permissionMap.getOrDefault(dictType, Collections.emptySet());
|
||||
return extractDictItems(this.buildChildNode(dictType), selectedSet).stream();
|
||||
}
|
||||
return Stream.empty();
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从节点子项中提取字典项,并构建按钮权限视图对象列表
|
||||
*
|
||||
* @param childNode 子节点
|
||||
* @param selectedSet 已选中的值集
|
||||
* @return 按钮权限视图对象列表
|
||||
*/
|
||||
private List<ButtonPermissionVo> extractDictItems(NodeExt.ChildNode childNode, Set<String> selectedSet) {
|
||||
return Optional.ofNullable(childNode)
|
||||
.map(NodeExt.ChildNode::getDict)
|
||||
.orElse(List.of())
|
||||
.stream()
|
||||
.map(dict -> new ButtonPermissionVo(dict.getValue(), selectedSet.contains(dict.getValue())))
|
||||
.toList();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.domain.dto.DeptDTO;
|
||||
import com.fuyuanshen.common.core.domain.dto.TaskAssigneeDTO;
|
||||
import com.fuyuanshen.common.core.domain.dto.UserDTO;
|
||||
import com.fuyuanshen.common.core.domain.model.TaskAssigneeBody;
|
||||
import com.fuyuanshen.common.core.enums.FormatsType;
|
||||
import com.fuyuanshen.common.core.service.DeptService;
|
||||
import com.fuyuanshen.common.core.service.TaskAssigneeService;
|
||||
import com.fuyuanshen.common.core.service.UserService;
|
||||
import com.fuyuanshen.common.core.utils.DateUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.enums.TaskAssigneeEnum;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskAssigneeService;
|
||||
import org.dromara.warm.flow.ui.dto.HandlerFunDto;
|
||||
import org.dromara.warm.flow.ui.dto.HandlerQuery;
|
||||
import org.dromara.warm.flow.ui.dto.TreeFunDto;
|
||||
import org.dromara.warm.flow.ui.service.HandlerSelectService;
|
||||
import org.dromara.warm.flow.ui.vo.HandlerFeedBackVo;
|
||||
import org.dromara.warm.flow.ui.vo.HandlerSelectVo;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 流程设计器-获取办理人权限设置列表
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, HandlerSelectService {
|
||||
|
||||
private static final String DEFAULT_GROUP_NAME = "默认分组";
|
||||
private final TaskAssigneeService taskAssigneeService;
|
||||
private final UserService userService;
|
||||
private final DeptService deptService;
|
||||
|
||||
/**
|
||||
* 获取办理人权限设置列表tabs页签
|
||||
*
|
||||
* @return tabs页签
|
||||
*/
|
||||
@Override
|
||||
public List<String> getHandlerType() {
|
||||
return TaskAssigneeEnum.getAssigneeTypeList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取办理列表, 同时构建左侧部门树状结构
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return HandlerSelectVo
|
||||
*/
|
||||
@Override
|
||||
public HandlerSelectVo getHandlerSelect(HandlerQuery query) {
|
||||
// 获取任务办理类型
|
||||
TaskAssigneeEnum type = TaskAssigneeEnum.fromDesc(query.getHandlerType());
|
||||
// 转换查询条件为 TaskAssigneeBody
|
||||
TaskAssigneeBody taskQuery = BeanUtil.toBean(query, TaskAssigneeBody.class);
|
||||
|
||||
// 统一查询并构建业务数据
|
||||
TaskAssigneeDTO dto = fetchTaskAssigneeData(type, taskQuery);
|
||||
List<DeptDTO> depts = fetchDeptData(type);
|
||||
|
||||
return getHandlerSelectVo(buildHandlerData(dto, type), buildDeptTree(depts));
|
||||
}
|
||||
|
||||
/**
|
||||
* 办理人权限名称回显
|
||||
*
|
||||
* @param storageIds 入库主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public List<HandlerFeedBackVo> handlerFeedback(List<String> storageIds) {
|
||||
if (CollUtil.isEmpty(storageIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 解析并归类 ID,同时记录原始顺序和对应解析结果
|
||||
Map<TaskAssigneeEnum, List<Long>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
||||
Map<String, Pair<TaskAssigneeEnum, Long>> parsedMap = new LinkedHashMap<>();
|
||||
for (String storageId : storageIds) {
|
||||
Pair<TaskAssigneeEnum, Long> parsed = this.parseStorageId(storageId);
|
||||
parsedMap.put(storageId, parsed);
|
||||
if (parsed != null) {
|
||||
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// 查询所有类型对应的 ID 名称映射
|
||||
Map<TaskAssigneeEnum, Map<Long, String>> nameMap = new EnumMap<>(TaskAssigneeEnum.class);
|
||||
typeIdMap.forEach((type, ids) -> nameMap.put(type, this.getNamesByType(type, ids)));
|
||||
|
||||
// 组装返回结果,保持原始顺序
|
||||
return parsedMap.entrySet().stream()
|
||||
.map(entry -> {
|
||||
String storageId = entry.getKey();
|
||||
Pair<TaskAssigneeEnum, Long> parsed = entry.getValue();
|
||||
String handlerName = "格式错误";
|
||||
if (parsed != null) {
|
||||
Map<Long, String> nameMapping = nameMap.getOrDefault(parsed.getKey(), Collections.emptyMap());
|
||||
handlerName = nameMapping.getOrDefault(parsed.getValue(), "未知名称");
|
||||
}
|
||||
HandlerFeedBackVo backVo = new HandlerFeedBackVo();
|
||||
backVo.setStorageId(storageId);
|
||||
backVo.setHandlerName(handlerName);
|
||||
return backVo;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据任务办理类型查询对应的数据
|
||||
*/
|
||||
private TaskAssigneeDTO fetchTaskAssigneeData(TaskAssigneeEnum type, TaskAssigneeBody taskQuery) {
|
||||
return switch (type) {
|
||||
case USER -> taskAssigneeService.selectUsersByTaskAssigneeList(taskQuery);
|
||||
case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery);
|
||||
case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery);
|
||||
case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据任务办理类型获取部门数据
|
||||
*/
|
||||
private List<DeptDTO> fetchDeptData(TaskAssigneeEnum type) {
|
||||
if (type == TaskAssigneeEnum.USER || type == TaskAssigneeEnum.DEPT || type == TaskAssigneeEnum.POST) {
|
||||
return deptService.selectDeptsByList();
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建部门树状结构
|
||||
*/
|
||||
private TreeFunDto<DeptDTO> buildDeptTree(List<DeptDTO> depts) {
|
||||
return new TreeFunDto<>(depts)
|
||||
.setId(dept -> String.valueOf(dept.getDeptId()))
|
||||
.setName(DeptDTO::getDeptName)
|
||||
.setParentId(dept -> String.valueOf(dept.getParentId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建任务办理人数据
|
||||
*/
|
||||
private HandlerFunDto<TaskAssigneeDTO.TaskHandler> buildHandlerData(TaskAssigneeDTO dto, TaskAssigneeEnum type) {
|
||||
return new HandlerFunDto<>(dto.getList(), dto.getTotal())
|
||||
.setStorageId(assignee -> type.getCode() + assignee.getStorageId())
|
||||
.setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "无"))
|
||||
.setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "无"))
|
||||
.setGroupName(assignee -> StringUtils.defaultIfBlank(
|
||||
Optional.ofNullable(assignee.getGroupName())
|
||||
.map(deptService::selectDeptNameByIds)
|
||||
.orElse(DEFAULT_GROUP_NAME), DEFAULT_GROUP_NAME))
|
||||
.setCreateTime(assignee -> DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, assignee.getCreateTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量解析多个存储标识符(storageIds),按类型分类并合并查询用户列表
|
||||
* 输入格式支持多个以逗号分隔的标识(如 "user:123,role:456,789")
|
||||
* 会自动去重返回结果,非法格式的标识将被忽略
|
||||
*
|
||||
* @param storageIds 多个存储标识符字符串(逗号分隔)
|
||||
* @return 合并后的用户列表,去重后返回,非法格式的标识将被跳过
|
||||
*/
|
||||
@Override
|
||||
public List<UserDTO> fetchUsersByStorageIds(String storageIds) {
|
||||
if (StringUtils.isEmpty(storageIds)) {
|
||||
return List.of();
|
||||
}
|
||||
Map<TaskAssigneeEnum, List<Long>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
||||
for (String storageId : storageIds.split(StringUtils.SEPARATOR)) {
|
||||
Pair<TaskAssigneeEnum, Long> parsed = this.parseStorageId(storageId);
|
||||
if (parsed != null) {
|
||||
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
||||
}
|
||||
}
|
||||
return typeIdMap.entrySet().stream()
|
||||
.flatMap(entry -> this.getUsersByType(entry.getKey(), entry.getValue()).stream())
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的任务分配类型(TaskAssigneeEnum)和 ID 列表,获取对应的用户信息列表
|
||||
*
|
||||
* @param type 任务分配类型,表示用户、角色、部门或其他(TaskAssigneeEnum 枚举值)
|
||||
* @param ids 与指定分配类型关联的 ID 列表(例如用户ID、角色ID、部门ID等)
|
||||
* @return 返回包含用户信息的列表。如果类型为用户(USER),则通过用户ID列表查询;
|
||||
* 如果类型为角色(ROLE),则通过角色ID列表查询;
|
||||
* 如果类型为部门(DEPT),则通过部门ID列表查询;
|
||||
* 如果类型为岗位(POST)或无法识别的类型,则返回空列表
|
||||
*/
|
||||
private List<UserDTO> getUsersByType(TaskAssigneeEnum type, List<Long> ids) {
|
||||
return switch (type) {
|
||||
case USER -> userService.selectListByIds(ids);
|
||||
case ROLE -> userService.selectUsersByRoleIds(ids);
|
||||
case DEPT -> userService.selectUsersByDeptIds(ids);
|
||||
case POST -> userService.selectUsersByPostIds(ids);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据任务分配类型和对应 ID 列表,批量查询名称映射关系
|
||||
*
|
||||
* @param type 分配类型(用户、角色、部门、岗位)
|
||||
* @param ids ID 列表(如用户ID、角色ID等)
|
||||
* @return 返回 Map,其中 key 为 ID,value 为对应的名称
|
||||
*/
|
||||
private Map<Long, String> getNamesByType(TaskAssigneeEnum type, List<Long> ids) {
|
||||
return switch (type) {
|
||||
case USER -> userService.selectUserNamesByIds(ids);
|
||||
case ROLE -> userService.selectRoleNamesByIds(ids);
|
||||
case DEPT -> userService.selectDeptNamesByIds(ids);
|
||||
case POST -> userService.selectPostNamesByIds(ids);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 storageId 字符串,返回类型和ID的组合
|
||||
*
|
||||
* @param storageId 例如 "user:123" 或 "456"
|
||||
* @return Pair(TaskAssigneeEnum, Long),如果格式非法返回 null
|
||||
*/
|
||||
private Pair<TaskAssigneeEnum, Long> parseStorageId(String storageId) {
|
||||
try {
|
||||
String[] parts = storageId.split(StrUtil.COLON, 2);
|
||||
if (parts.length < 2) {
|
||||
return Pair.of(TaskAssigneeEnum.USER, Long.valueOf(parts[0]));
|
||||
} else {
|
||||
TaskAssigneeEnum type = TaskAssigneeEnum.fromCode(parts[0] + StrUtil.COLON);
|
||||
return Pair.of(type, Long.valueOf(parts[1]));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析 storageId 失败,格式非法:{},错误信息:{}", storageId, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,752 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.domain.dto.StartProcessReturnDTO;
|
||||
import com.fuyuanshen.common.core.domain.dto.UserDTO;
|
||||
import com.fuyuanshen.common.core.enums.BusinessStatusEnum;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.core.service.UserService;
|
||||
import com.fuyuanshen.common.core.utils.StreamUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.core.utils.ValidatorUtils;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.common.constant.FlowConstant;
|
||||
import com.fuyuanshen.workflow.common.enums.TaskAssigneeType;
|
||||
import com.fuyuanshen.workflow.common.enums.TaskStatusEnum;
|
||||
import com.fuyuanshen.workflow.domain.bo.*;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowHisTaskVo;
|
||||
import com.fuyuanshen.workflow.domain.vo.FlowTaskVo;
|
||||
import com.fuyuanshen.workflow.mapper.FlwCategoryMapper;
|
||||
import com.fuyuanshen.workflow.mapper.FlwTaskMapper;
|
||||
import com.fuyuanshen.workflow.service.IFlwCommonService;
|
||||
import com.fuyuanshen.workflow.service.IFlwNodeExtService;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskAssigneeService;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskService;
|
||||
import org.dromara.warm.flow.core.FlowEngine;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.entity.*;
|
||||
import org.dromara.warm.flow.core.enums.NodeType;
|
||||
import org.dromara.warm.flow.core.enums.SkipType;
|
||||
import org.dromara.warm.flow.core.service.*;
|
||||
import org.dromara.warm.flow.core.utils.ExpressionUtil;
|
||||
import org.dromara.warm.flow.core.utils.MapUtil;
|
||||
import org.dromara.warm.flow.orm.entity.*;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.fuyuanshen.workflow.common.constant.FlowConstant.*;
|
||||
|
||||
/**
|
||||
* 任务 服务层实现
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
|
||||
private final TaskService taskService;
|
||||
private final InsService insService;
|
||||
private final DefService defService;
|
||||
private final HisTaskService hisTaskService;
|
||||
private final NodeService nodeService;
|
||||
private final FlowInstanceMapper flowInstanceMapper;
|
||||
private final FlowTaskMapper flowTaskMapper;
|
||||
private final FlowHisTaskMapper flowHisTaskMapper;
|
||||
private final IdentifierGenerator identifierGenerator;
|
||||
private final UserService userService;
|
||||
private final FlwTaskMapper flwTaskMapper;
|
||||
private final FlwCategoryMapper flwCategoryMapper;
|
||||
private final FlowNodeMapper flowNodeMapper;
|
||||
private final IFlwTaskAssigneeService flwTaskAssigneeService;
|
||||
private final IFlwCommonService flwCommonService;
|
||||
private final IFlwNodeExtService flwNodeExtService;
|
||||
|
||||
/**
|
||||
* 启动任务
|
||||
*
|
||||
* @param startProcessBo 启动流程参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) {
|
||||
String businessId = startProcessBo.getBusinessId();
|
||||
if (StringUtils.isBlank(businessId)) {
|
||||
throw new ServiceException("启动工作流时必须包含业务ID");
|
||||
}
|
||||
// 启动流程实例(提交申请)
|
||||
Map<String, Object> variables = startProcessBo.getVariables();
|
||||
// 流程发起人
|
||||
variables.put(INITIATOR, LoginHelper.getUserIdStr());
|
||||
// 业务id
|
||||
variables.put(BUSINESS_ID, businessId);
|
||||
FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class)
|
||||
.eq(FlowInstance::getBusinessId, businessId));
|
||||
if (ObjectUtil.isNotNull(flowInstance)) {
|
||||
BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus());
|
||||
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId()));
|
||||
taskService.mergeVariable(flowInstance, variables);
|
||||
insService.updateById(flowInstance);
|
||||
StartProcessReturnDTO dto = new StartProcessReturnDTO();
|
||||
dto.setProcessInstanceId(taskList.get(0).getInstanceId());
|
||||
dto.setTaskId(taskList.get(0).getId());
|
||||
return dto;
|
||||
}
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.flowCode(startProcessBo.getFlowCode())
|
||||
.variable(startProcessBo.getVariables())
|
||||
.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||
Instance instance;
|
||||
try {
|
||||
instance = insService.start(businessId, flowParams);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
// 申请人执行流程
|
||||
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId()));
|
||||
if (taskList.size() > 1) {
|
||||
throw new ServiceException("请检查流程第一个环节是否为申请人!");
|
||||
}
|
||||
StartProcessReturnDTO dto = new StartProcessReturnDTO();
|
||||
dto.setProcessInstanceId(instance.getId());
|
||||
dto.setTaskId(taskList.get(0).getId());
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 办理任务
|
||||
*
|
||||
* @param completeTaskBo 办理任务参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean completeTask(CompleteTaskBo completeTaskBo) {
|
||||
try {
|
||||
// 获取任务ID并查询对应的流程任务和实例信息
|
||||
Long taskId = completeTaskBo.getTaskId();
|
||||
List<String> messageType = completeTaskBo.getMessageType();
|
||||
String notice = completeTaskBo.getNotice();
|
||||
// 获取抄送人
|
||||
List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
|
||||
// 设置抄送人
|
||||
completeTaskBo.getVariables().put(FlowConstant.FLOW_COPY_LIST, flowCopyList);
|
||||
// 消息类型
|
||||
completeTaskBo.getVariables().put(FlowConstant.MESSAGE_TYPE, messageType);
|
||||
// 消息通知
|
||||
completeTaskBo.getVariables().put(FlowConstant.MESSAGE_NOTICE, notice);
|
||||
|
||||
|
||||
FlowTask flowTask = flowTaskMapper.selectById(taskId);
|
||||
if (ObjectUtil.isNull(flowTask)) {
|
||||
throw new ServiceException("流程任务不存在或任务已审批!");
|
||||
}
|
||||
Instance ins = insService.getById(flowTask.getInstanceId());
|
||||
// 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听
|
||||
if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) {
|
||||
completeTaskBo.getVariables().put(FlowConstant.SUBMIT, true);
|
||||
}
|
||||
// 设置弹窗处理人
|
||||
Map<String, Object> assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap());
|
||||
if (CollUtil.isNotEmpty(assigneeMap)) {
|
||||
completeTaskBo.getVariables().putAll(assigneeMap);
|
||||
}
|
||||
// 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.variable(completeTaskBo.getVariables())
|
||||
.skipType(SkipType.PASS.getKey())
|
||||
.message(completeTaskBo.getMessage())
|
||||
.flowStatus(BusinessStatusEnum.WAITING.getStatus())
|
||||
.hisStatus(TaskStatusEnum.PASS.getStatus())
|
||||
.hisTaskExt(completeTaskBo.getFileId());
|
||||
// 执行任务跳转,并根据返回的处理人设置下一步处理人
|
||||
taskService.skip(taskId, flowParams);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置弹窗处理人
|
||||
*
|
||||
* @param assigneeMap 处理人
|
||||
* @param variablesMap 变量
|
||||
*/
|
||||
private Map<String, Object> setPopAssigneeMap(Map<String, Object> assigneeMap, Map<String, Object> variablesMap) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (CollUtil.isEmpty(assigneeMap)) {
|
||||
return map;
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : assigneeMap.entrySet()) {
|
||||
if (variablesMap.containsKey(entry.getKey())) {
|
||||
String userIds = variablesMap.get(entry.getKey()).toString();
|
||||
if (StringUtils.isNotBlank(userIds)) {
|
||||
Set<String> hashSet = new HashSet<>();
|
||||
//弹窗传入的选人
|
||||
List<String> popUserIds = Arrays.asList(entry.getValue().toString().split(StringUtils.SEPARATOR));
|
||||
//已有的选人
|
||||
List<String> variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR));
|
||||
hashSet.addAll(popUserIds);
|
||||
hashSet.addAll(variableUserIds);
|
||||
map.put(entry.getKey(), String.join(StringUtils.SEPARATOR, hashSet));
|
||||
}
|
||||
} else {
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加抄送人
|
||||
*
|
||||
* @param task 任务信息
|
||||
* @param flowCopyList 抄送人
|
||||
*/
|
||||
@Override
|
||||
public void setCopy(Task task, List<FlowCopyBo> flowCopyList) {
|
||||
if (CollUtil.isEmpty(flowCopyList)) {
|
||||
return;
|
||||
}
|
||||
// 添加抄送人记录
|
||||
FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0);
|
||||
FlowNode flowNode = new FlowNode();
|
||||
flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
|
||||
flowNode.setNodeName(flowHisTask.getTargetNodeName());
|
||||
//生成新的任务id
|
||||
long taskId = identifierGenerator.nextId(null).longValue();
|
||||
task.setId(taskId);
|
||||
task.setNodeName("【抄送】" + task.getNodeName());
|
||||
Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000);
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.skipType(SkipType.NONE.getKey())
|
||||
.hisStatus(TaskStatusEnum.COPY.getStatus())
|
||||
.message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName));
|
||||
HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams);
|
||||
hisTask.setCreateTime(updateTime);
|
||||
hisTask.setUpdateTime(updateTime);
|
||||
hisTaskService.save(hisTask);
|
||||
List<User> userList = flowCopyList.stream()
|
||||
.map(flowCopy -> {
|
||||
FlowUser flowUser = new FlowUser();
|
||||
flowUser.setType(TaskAssigneeType.COPY.getCode());
|
||||
flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId()));
|
||||
flowUser.setAssociated(taskId);
|
||||
return flowUser;
|
||||
}).collect(Collectors.toList());
|
||||
// 批量保存抄送人员
|
||||
FlowEngine.userService().saveBatch(userList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的待办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
||||
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
|
||||
queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus());
|
||||
Page<FlowTaskVo> page = this.getFlowTaskVoPage(pageQuery, queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的已办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
||||
queryWrapper.in("t.approver", LoginHelper.getUserIdStr());
|
||||
queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
|
||||
Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询待办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
||||
Page<FlowTaskVo> page = getFlowTaskVoPage(pageQuery, queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
private Page<FlowTaskVo> getFlowTaskVoPage(PageQuery pageQuery, QueryWrapper<FlowTaskBo> queryWrapper) {
|
||||
Page<FlowTaskVo> page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper);
|
||||
List<FlowTaskVo> records = page.getRecords();
|
||||
if (CollUtil.isNotEmpty(records)) {
|
||||
List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId);
|
||||
Map<Long, List<UserDTO>> listMap = currentTaskAllUser(taskIds);
|
||||
records.forEach(t -> {
|
||||
List<UserDTO> userList = listMap.getOrDefault(t.getId(), Collections.emptyList());
|
||||
if (CollUtil.isNotEmpty(userList)) {
|
||||
t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId())));
|
||||
t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName));
|
||||
}
|
||||
});
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已办任务
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||
Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的抄送
|
||||
*
|
||||
* @param flowTaskBo 参数
|
||||
* @param pageQuery 分页
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
|
||||
Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
private QueryWrapper<FlowTaskBo> buildQueryWrapper(FlowTaskBo flowTaskBo) {
|
||||
QueryWrapper<FlowTaskBo> wrapper = Wrappers.query();
|
||||
wrapper.like(StringUtils.isNotBlank(flowTaskBo.getNodeName()), "t.node_name", flowTaskBo.getNodeName());
|
||||
wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowName()), "t.flow_name", flowTaskBo.getFlowName());
|
||||
wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode());
|
||||
wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds());
|
||||
if (StringUtils.isNotBlank(flowTaskBo.getCategory())) {
|
||||
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
|
||||
wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr));
|
||||
}
|
||||
wrapper.orderByDesc("t.create_time");
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回任务
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean backProcess(BackProcessBo bo) {
|
||||
try {
|
||||
Long taskId = bo.getTaskId();
|
||||
String notice = bo.getNotice();
|
||||
List<String> messageType = bo.getMessageType();
|
||||
String message = bo.getMessage();
|
||||
FlowTask task = flowTaskMapper.selectById(taskId);
|
||||
if (ObjectUtil.isNull(task)) {
|
||||
throw new ServiceException("任务不存在!");
|
||||
}
|
||||
Instance inst = insService.getById(task.getInstanceId());
|
||||
BusinessStatusEnum.checkBackStatus(inst.getFlowStatus());
|
||||
Long definitionId = task.getDefinitionId();
|
||||
String applyNodeCode = flwCommonService.applyNodeCode(definitionId);
|
||||
|
||||
Map<String, Object> variable = new HashMap<>();
|
||||
// 消息类型
|
||||
variable.put("messageType", messageType);
|
||||
// 消息通知
|
||||
variable.put("notice", notice);
|
||||
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.nodeCode(bo.getNodeCode())
|
||||
.variable(variable)
|
||||
.message(message)
|
||||
.skipType(SkipType.REJECT.getKey())
|
||||
.flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus())
|
||||
.hisStatus(TaskStatusEnum.BACK.getStatus())
|
||||
.hisTaskExt(bo.getFileId());
|
||||
taskService.skip(task.getId(), flowParams);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可驳回的前置节点
|
||||
*
|
||||
* @param definitionId 流程定义id
|
||||
* @param nowNodeCode 当前节点
|
||||
*/
|
||||
@Override
|
||||
public List<Node> getBackTaskNode(Long definitionId, String nowNodeCode) {
|
||||
List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId);
|
||||
if (!CollUtil.isNotEmpty(nodeCodes)) {
|
||||
return nodeCodes;
|
||||
}
|
||||
//判断是否配置了固定驳回节点
|
||||
Node node = nodeCodes.get(0);
|
||||
if (StringUtils.isNotBlank(node.getAnyNodeSkip())) {
|
||||
return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId);
|
||||
}
|
||||
//获取可驳回的前置节点
|
||||
List<Node> nodes = nodeService.previousNodeList(definitionId, nowNodeCode);
|
||||
if (CollUtil.isNotEmpty(nodes)) {
|
||||
return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 终止任务
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean terminationTask(FlowTerminationBo bo) {
|
||||
try {
|
||||
Long taskId = bo.getTaskId();
|
||||
Task task = taskService.getById(taskId);
|
||||
if (task == null) {
|
||||
throw new ServiceException("任务不存在!");
|
||||
}
|
||||
Instance instance = insService.getById(task.getInstanceId());
|
||||
if (ObjectUtil.isNotNull(instance)) {
|
||||
BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
|
||||
}
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.message(bo.getComment())
|
||||
.flowStatus(BusinessStatusEnum.TERMINATION.getStatus())
|
||||
.hisStatus(TaskStatusEnum.TERMINATION.getStatus());
|
||||
taskService.termination(taskId, flowParams);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
*/
|
||||
@Override
|
||||
public List<FlowTask> selectByIdList(List<Long> taskIdList) {
|
||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
||||
.in(FlowTask::getId, taskIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
@Override
|
||||
public FlowTaskVo selectById(Long taskId) {
|
||||
Task task = taskService.getById(taskId);
|
||||
if (ObjectUtil.isNull(task)) {
|
||||
return null;
|
||||
}
|
||||
FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class);
|
||||
Instance instance = insService.getById(task.getInstanceId());
|
||||
Definition definition = defService.getById(task.getDefinitionId());
|
||||
flowTaskVo.setFlowStatus(instance.getFlowStatus());
|
||||
flowTaskVo.setVersion(definition.getVersion());
|
||||
flowTaskVo.setFlowCode(definition.getFlowCode());
|
||||
flowTaskVo.setFlowName(definition.getFlowName());
|
||||
flowTaskVo.setBusinessId(instance.getBusinessId());
|
||||
FlowNode flowNode = this.getByNodeCode(flowTaskVo.getNodeCode(), instance.getDefinitionId());
|
||||
if (ObjectUtil.isNull(flowNode)) {
|
||||
throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
|
||||
}
|
||||
//设置按钮权限
|
||||
flowTaskVo.setButtonList(flwNodeExtService.buildButtonPermissionsFromExt(flowNode.getExt()));
|
||||
flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
|
||||
flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
|
||||
return flowTaskVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一节点信息
|
||||
*
|
||||
* @param bo 参数
|
||||
*/
|
||||
@Override
|
||||
public List<FlowNode> getNextNodeList(FlowNextNodeBo bo) {
|
||||
Long taskId = bo.getTaskId();
|
||||
Map<String, Object> variables = bo.getVariables();
|
||||
Task task = taskService.getById(taskId);
|
||||
Instance instance = insService.getById(task.getInstanceId());
|
||||
Definition definition = defService.getById(task.getDefinitionId());
|
||||
Map<String, Object> mergeVariable = MapUtil.mergeAll(instance.getVariableMap(), variables);
|
||||
// 获取下一节点列表
|
||||
List<Node> nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null, SkipType.PASS.getKey(), mergeVariable);
|
||||
List<FlowNode> nextFlowNodes = BeanUtil.copyToList(nextNodeList, FlowNode.class);
|
||||
// 只获取中间节点
|
||||
nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType()));
|
||||
if (CollUtil.isNotEmpty(nextNodeList)) {
|
||||
// 构建以下节点数据
|
||||
List<Task> buildNextTaskList = StreamUtils.toList(nextNodeList, node -> taskService.addTask(node, instance, definition, FlowParams.build()));
|
||||
// 办理人变量替换
|
||||
ExpressionUtil.evalVariable(buildNextTaskList, mergeVariable);
|
||||
for (FlowNode flowNode : nextFlowNodes) {
|
||||
buildNextTaskList.stream().filter(t -> t.getNodeCode().equals(flowNode.getNodeCode())).findFirst().ifPresent(t -> {
|
||||
if (CollUtil.isNotEmpty(t.getPermissionList())) {
|
||||
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList()));
|
||||
if (CollUtil.isNotEmpty(users)) {
|
||||
flowNode.setPermissionFlag(StreamUtils.join(users, e -> String.valueOf(e.getUserId())));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return nextFlowNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList) {
|
||||
return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class)
|
||||
.in(FlowHisTask::getId, taskIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照任务id查询任务
|
||||
*
|
||||
* @param taskId 任务id
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public FlowHisTask selectHisTaskById(Long taskId) {
|
||||
return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class)
|
||||
.eq(FlowHisTask::getId, taskId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照实例id查询任务
|
||||
*
|
||||
* @param instanceIdList 流程实例id
|
||||
*/
|
||||
@Override
|
||||
public List<FlowTask> selectByInstIdList(List<Long> instanceIdList) {
|
||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
||||
.in(FlowTask::getInstanceId, instanceIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照实例id查询任务
|
||||
*
|
||||
* @param instanceId 流程实例id
|
||||
*/
|
||||
@Override
|
||||
public List<FlowTask> selectByInstId(Long instanceId) {
|
||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
||||
.eq(FlowTask::getInstanceId, instanceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务操作
|
||||
*
|
||||
* @param bo 参数
|
||||
* @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.message(bo.getMessage());
|
||||
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
||||
flowParams.ignore(true);
|
||||
}
|
||||
|
||||
// 根据操作类型构建 FlowParams
|
||||
switch (taskOperation) {
|
||||
case DELEGATE_TASK, TRANSFER_TASK -> {
|
||||
ValidatorUtils.validate(bo, AddGroup.class);
|
||||
flowParams.addHandlers(Collections.singletonList(bo.getUserId()));
|
||||
}
|
||||
case ADD_SIGNATURE -> {
|
||||
ValidatorUtils.validate(bo, EditGroup.class);
|
||||
flowParams.addHandlers(bo.getUserIds());
|
||||
}
|
||||
case REDUCTION_SIGNATURE -> {
|
||||
ValidatorUtils.validate(bo, EditGroup.class);
|
||||
flowParams.reductionHandlers(bo.getUserIds());
|
||||
}
|
||||
default -> {
|
||||
log.error("Invalid operation type:{} ", taskOperation);
|
||||
throw new ServiceException("Invalid operation type " + taskOperation);
|
||||
}
|
||||
}
|
||||
|
||||
Long taskId = bo.getTaskId();
|
||||
Task task = taskService.getById(taskId);
|
||||
FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId());
|
||||
if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) {
|
||||
if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new ServiceException(task.getNodeName() + "不是会签节点!");
|
||||
}
|
||||
}
|
||||
// 设置任务状态并执行对应的任务操作
|
||||
switch (taskOperation) {
|
||||
//委派任务
|
||||
case DELEGATE_TASK -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus());
|
||||
return taskService.depute(taskId, flowParams);
|
||||
}
|
||||
//转办任务
|
||||
case TRANSFER_TASK -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus());
|
||||
return taskService.transfer(taskId, flowParams);
|
||||
}
|
||||
//加签,增加办理人
|
||||
case ADD_SIGNATURE -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus());
|
||||
return taskService.addSignature(taskId, flowParams);
|
||||
}
|
||||
//减签,减少办理人
|
||||
case REDUCTION_SIGNATURE -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus());
|
||||
return taskService.reductionSignature(taskId, flowParams);
|
||||
}
|
||||
default -> {
|
||||
log.error("Invalid operation type:{} ", taskOperation);
|
||||
throw new ServiceException("Invalid operation type " + taskOperation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改任务办理人(此方法将会批量修改所有任务的办理人)
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
* @param userId 用户id
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean updateAssignee(List<Long> taskIdList, String userId) {
|
||||
if (CollUtil.isEmpty(taskIdList)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
List<FlowTask> flowTasks = this.selectByIdList(taskIdList);
|
||||
// 批量删除现有任务的办理人记录
|
||||
if (CollUtil.isNotEmpty(flowTasks)) {
|
||||
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
|
||||
List<User> userList = flowTasks.stream()
|
||||
.map(flowTask -> {
|
||||
FlowUser flowUser = new FlowUser();
|
||||
flowUser.setType(TaskAssigneeType.APPROVER.getCode());
|
||||
flowUser.setProcessedBy(userId);
|
||||
flowUser.setAssociated(flowTask.getId());
|
||||
return flowUser;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isNotEmpty(userList)) {
|
||||
FlowEngine.userService().saveBatch(userList);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务所有办理人
|
||||
*
|
||||
* @param taskIdList 任务id
|
||||
*/
|
||||
@Override
|
||||
public Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList) {
|
||||
Map<Long, List<UserDTO>> map = new HashMap<>();
|
||||
// 获取与当前任务关联的用户列表
|
||||
List<User> associatedUsers = FlowEngine.userService().getByAssociateds(taskIdList);
|
||||
Map<Long, List<User>> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
|
||||
for (Map.Entry<Long, List<User>> entry : listMap.entrySet()) {
|
||||
List<User> value = entry.getValue();
|
||||
if (CollUtil.isNotEmpty(value)) {
|
||||
List<UserDTO> userDtoList = userService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy())));
|
||||
map.put(entry.getKey(), userDtoList);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前任务的所有办理人
|
||||
*
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
@Override
|
||||
public List<UserDTO> currentTaskAllUser(Long taskId) {
|
||||
// 获取与当前任务关联的用户列表
|
||||
List<User> userList = FlowEngine.userService().getByAssociateds(Collections.singletonList(taskId));
|
||||
if (CollUtil.isEmpty(userList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return userService.selectListByIds(StreamUtils.toList(userList, e -> Long.valueOf(e.getProcessedBy())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照节点编码查询节点
|
||||
*
|
||||
* @param nodeCode 节点编码
|
||||
* @param definitionId 流程定义id
|
||||
*/
|
||||
@Override
|
||||
public FlowNode getByNodeCode(String nodeCode, Long definitionId) {
|
||||
return flowNodeMapper.selectOne(new LambdaQueryWrapper<FlowNode>()
|
||||
.eq(FlowNode::getNodeCode, nodeCode)
|
||||
.eq(FlowNode::getDefinitionId, definitionId));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.common.core.domain.event.ProcessTaskEvent;
|
||||
import com.fuyuanshen.common.core.domain.event.ProcessDeleteEvent;
|
||||
import com.fuyuanshen.common.core.domain.event.ProcessEvent;
|
||||
import com.fuyuanshen.common.core.enums.BusinessStatusEnum;
|
||||
import com.fuyuanshen.common.core.service.WorkflowService;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.domain.TestLeave;
|
||||
import com.fuyuanshen.workflow.domain.bo.TestLeaveBo;
|
||||
import com.fuyuanshen.workflow.domain.vo.TestLeaveVo;
|
||||
import com.fuyuanshen.workflow.mapper.TestLeaveMapper;
|
||||
import com.fuyuanshen.workflow.service.ITestLeaveService;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 请假Service业务层处理
|
||||
*
|
||||
* @author may
|
||||
* @date 2023-07-21
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@Slf4j
|
||||
public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
|
||||
private final TestLeaveMapper baseMapper;
|
||||
private final WorkflowService workflowService;
|
||||
|
||||
/**
|
||||
* spel条件表达:判断小于2
|
||||
*
|
||||
* @param leaveDays 待判断的变量(可不传自行返回true或false)
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean eval(Integer leaveDays) {
|
||||
if (leaveDays <= 2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询请假
|
||||
*/
|
||||
@Override
|
||||
public TestLeaveVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询请假列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<TestLeaveVo> queryPageList(TestLeaveBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<TestLeave> lqw = buildQueryWrapper(bo);
|
||||
Page<TestLeaveVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询请假列表
|
||||
*/
|
||||
@Override
|
||||
public List<TestLeaveVo> queryList(TestLeaveBo bo) {
|
||||
LambdaQueryWrapper<TestLeave> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<TestLeave> buildQueryWrapper(TestLeaveBo bo) {
|
||||
LambdaQueryWrapper<TestLeave> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), TestLeave::getLeaveType, bo.getLeaveType());
|
||||
lqw.ge(bo.getStartLeaveDays() != null, TestLeave::getLeaveDays, bo.getStartLeaveDays());
|
||||
lqw.le(bo.getEndLeaveDays() != null, TestLeave::getLeaveDays, bo.getEndLeaveDays());
|
||||
lqw.orderByDesc(BaseEntity::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增请假
|
||||
*/
|
||||
@Override
|
||||
public TestLeaveVo insertByBo(TestLeaveBo bo) {
|
||||
long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true);
|
||||
// 截止日期也算一天
|
||||
bo.setLeaveDays((int) day + 1);
|
||||
TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
|
||||
if (StringUtils.isBlank(add.getStatus())) {
|
||||
add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||
}
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return MapstructUtils.convert(add, TestLeaveVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改请假
|
||||
*/
|
||||
@Override
|
||||
public TestLeaveVo updateByBo(TestLeaveBo bo) {
|
||||
TestLeave update = MapstructUtils.convert(bo, TestLeave.class);
|
||||
baseMapper.updateById(update);
|
||||
return MapstructUtils.convert(update, TestLeaveVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除请假
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(List<Long> ids) {
|
||||
workflowService.deleteInstance(ids);
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
||||
* 正常使用只需#processEvent.flowCode=='leave1'
|
||||
* 示例为了方便则使用startsWith匹配了全部示例key
|
||||
*
|
||||
* @param processEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processEvent.flowCode.startsWith('leave')")
|
||||
public void processHandler(ProcessEvent processEvent) {
|
||||
log.info("当前任务执行了{}", processEvent.toString());
|
||||
TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId()));
|
||||
testLeave.setStatus(processEvent.getStatus());
|
||||
// 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程
|
||||
Map<String, Object> params = processEvent.getParams();
|
||||
if (MapUtil.isNotEmpty(params)) {
|
||||
// 历史任务扩展(通常为附件)
|
||||
String hisTaskExt = Convert.toStr(params.get("hisTaskExt"));
|
||||
// 办理人
|
||||
String handler = Convert.toStr(params.get("handler"));
|
||||
// 办理意见
|
||||
String message = Convert.toStr(params.get("message"));
|
||||
}
|
||||
if (processEvent.getSubmit()) {
|
||||
testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
|
||||
}
|
||||
baseMapper.updateById(testLeave);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行任务创建监听
|
||||
* 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断
|
||||
* 在方法中判断流程节点key
|
||||
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
|
||||
* //执行业务逻辑
|
||||
* }
|
||||
*
|
||||
* @param processTaskEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave')")
|
||||
public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
|
||||
log.info("当前任务创建了{}", processTaskEvent.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听删除流程事件
|
||||
* 正常使用只需#processDeleteEvent.flowCode=='leave1'
|
||||
* 示例为了方便则使用startsWith匹配了全部示例key
|
||||
*
|
||||
* @param processDeleteEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processDeleteEvent.flowCode.startsWith('leave')")
|
||||
public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) {
|
||||
log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString());
|
||||
TestLeave testLeave = baseMapper.selectById(Long.valueOf(processDeleteEvent.getBusinessId()));
|
||||
if (ObjectUtil.isNull(testLeave)) {
|
||||
return;
|
||||
}
|
||||
baseMapper.deleteById(testLeave.getId());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package com.fuyuanshen.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.common.core.domain.dto.CompleteTaskDTO;
|
||||
import com.fuyuanshen.common.core.domain.dto.StartProcessDTO;
|
||||
import com.fuyuanshen.common.core.domain.dto.StartProcessReturnDTO;
|
||||
import com.fuyuanshen.common.core.service.WorkflowService;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
import com.fuyuanshen.workflow.common.ConditionalOnEnable;
|
||||
import com.fuyuanshen.workflow.domain.bo.CompleteTaskBo;
|
||||
import com.fuyuanshen.workflow.domain.bo.StartProcessBo;
|
||||
import com.fuyuanshen.workflow.service.IFlwDefinitionService;
|
||||
import com.fuyuanshen.workflow.service.IFlwInstanceService;
|
||||
import com.fuyuanshen.workflow.service.IFlwTaskService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通用 工作流服务实现
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class WorkflowServiceImpl implements WorkflowService {
|
||||
|
||||
private final IFlwInstanceService flwInstanceService;
|
||||
private final IFlwDefinitionService flwDefinitionService;
|
||||
private final IFlwTaskService flwTaskService;
|
||||
|
||||
/**
|
||||
* 删除流程实例
|
||||
*
|
||||
* @param businessIds 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteInstance(List<Long> businessIds) {
|
||||
return flwInstanceService.deleteByBusinessIds(businessIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前流程状态
|
||||
*
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
@Override
|
||||
public String getBusinessStatusByTaskId(Long taskId) {
|
||||
FlowInstance flowInstance = flwInstanceService.selectByTaskId(taskId);
|
||||
return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前流程状态
|
||||
*
|
||||
* @param businessId 业务id
|
||||
*/
|
||||
@Override
|
||||
public String getBusinessStatus(String businessId) {
|
||||
FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId);
|
||||
return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置流程变量
|
||||
*
|
||||
* @param instanceId 流程实例id
|
||||
* @param variables 流程变量
|
||||
*/
|
||||
@Override
|
||||
public void setVariable(Long instanceId, Map<String, Object> variables) {
|
||||
flwInstanceService.setVariable(instanceId, variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程变量
|
||||
*
|
||||
* @param instanceId 流程实例id
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> instanceVariable(Long instanceId) {
|
||||
return flwInstanceService.instanceVariable(instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照业务id查询流程实例id
|
||||
*
|
||||
* @param businessId 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Long getInstanceIdByBusinessId(String businessId) {
|
||||
FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId);
|
||||
return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getId() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增租户流程定义
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
*/
|
||||
@Override
|
||||
public void syncDef(String tenantId) {
|
||||
flwDefinitionService.syncDef(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动流程
|
||||
*
|
||||
* @param startProcess 参数
|
||||
*/
|
||||
@Override
|
||||
public StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess) {
|
||||
return flwTaskService.startWorkFlow(BeanUtil.toBean(startProcess, StartProcessBo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 办理任务
|
||||
* 系统后台发起审批 无用户信息 需要忽略权限
|
||||
* completeTask.getVariables().put("ignore", true);
|
||||
*
|
||||
* @param completeTask 参数
|
||||
*/
|
||||
@Override
|
||||
public boolean completeTask(CompleteTaskDTO completeTask) {
|
||||
return flwTaskService.completeTask(BeanUtil.toBean(completeTask, CompleteTaskBo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 办理任务
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
* @param message 办理意见
|
||||
*/
|
||||
@Override
|
||||
public boolean completeTask(Long taskId, String message) {
|
||||
CompleteTaskBo completeTask = new CompleteTaskBo();
|
||||
completeTask.setTaskId(taskId);
|
||||
completeTask.setMessage(message);
|
||||
// 忽略权限(系统后台发起审批 无用户信息 需要忽略权限)
|
||||
completeTask.getVariables().put("ignore", true);
|
||||
return flwTaskService.completeTask(completeTask);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
java包使用 `.` 分割 resource 目录使用 `/` 分割
|
||||
<br>
|
||||
此文件目的 防止文件夹粘连找不到 `xml` 文件
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.dromara.workflow.mapper.FlwCategoryMapper">
|
||||
|
||||
<select id="countCategoryById" resultType="Long">
|
||||
select count(*) from flow_category where del_flag = '0' and category_id = #{categoryId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.dromara.workflow.mapper.FlwInstanceMapper">
|
||||
<resultMap type="com.fuyuanshen.workflow.domain.vo.FlowInstanceVo" id="FlowInstanceResult">
|
||||
</resultMap>
|
||||
|
||||
<select id="selectInstanceList" resultMap="FlowInstanceResult">
|
||||
select fi.id,
|
||||
fi.create_time,
|
||||
fi.update_time,
|
||||
fi.tenant_id,
|
||||
fi.del_flag,
|
||||
fi.definition_id,
|
||||
fi.business_id,
|
||||
fi.node_type,
|
||||
fi.node_code,
|
||||
fi.node_name,
|
||||
fi.variable,
|
||||
fi.flow_status,
|
||||
fi.activity_status,
|
||||
fi.create_by,
|
||||
fi.ext,
|
||||
fd.flow_name,
|
||||
fd.flow_code,
|
||||
fd.version,
|
||||
fd.form_custom,
|
||||
fd.form_path,
|
||||
fd.category
|
||||
from flow_instance fi
|
||||
left join flow_definition fd on fi.definition_id = fd.id
|
||||
${ew.getCustomSqlSegment}
|
||||
</select>
|
||||
|
||||
</mapper>
|
@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.dromara.workflow.mapper.FlwTaskMapper">
|
||||
<resultMap type="com.fuyuanshen.workflow.domain.vo.FlowTaskVo" id="FlowTaskResult">
|
||||
</resultMap>
|
||||
<resultMap type="com.fuyuanshen.workflow.domain.vo.FlowHisTaskVo" id="FlowHisTaskResult">
|
||||
</resultMap>
|
||||
|
||||
<select id="getListRunTask" resultMap="FlowTaskResult">
|
||||
select * from (
|
||||
select distinct
|
||||
t.id,
|
||||
t.node_code,
|
||||
t.node_name,
|
||||
t.node_type,
|
||||
t.definition_id,
|
||||
t.instance_id,
|
||||
t.create_time,
|
||||
t.update_time,
|
||||
t.tenant_id,
|
||||
i.business_id,
|
||||
i.flow_status,
|
||||
i.create_by,
|
||||
d.flow_name,
|
||||
d.flow_code,
|
||||
d.form_custom,
|
||||
d.category,
|
||||
COALESCE(t.form_path, d.form_path) as form_path,
|
||||
d.version,
|
||||
uu.processed_by,
|
||||
uu.type
|
||||
from flow_task t
|
||||
left join flow_user uu on uu.associated = t.id
|
||||
left join flow_definition d on t.definition_id = d.id
|
||||
left join flow_instance i on t.instance_id = i.id
|
||||
where t.node_type = 1
|
||||
and t.del_flag = '0'
|
||||
and uu.del_flag = '0'
|
||||
and uu.type in ('1','2','3')
|
||||
) t
|
||||
${ew.getCustomSqlSegment}
|
||||
</select>
|
||||
|
||||
<select id="getListFinishTask" resultMap="FlowHisTaskResult">
|
||||
select * from (
|
||||
select
|
||||
a.id,
|
||||
a.node_code,
|
||||
a.node_name,
|
||||
a.cooperate_type,
|
||||
a.approver,
|
||||
a.collaborator,
|
||||
a.node_type,
|
||||
a.target_node_code,
|
||||
a.target_node_name,
|
||||
a.definition_id,
|
||||
a.instance_id,
|
||||
a.flow_status flow_task_status,
|
||||
a.message,
|
||||
a.ext,
|
||||
a.create_time,
|
||||
a.update_time,
|
||||
a.tenant_id,
|
||||
a.form_custom,
|
||||
a.form_path,
|
||||
b.flow_status,
|
||||
b.business_id,
|
||||
b.create_by,
|
||||
c.flow_name,
|
||||
c.flow_code,
|
||||
c.category,
|
||||
c.version
|
||||
from flow_his_task a
|
||||
left join flow_instance b on a.instance_id = b.id
|
||||
left join flow_definition c on a.definition_id = c.id
|
||||
where a.del_flag ='0'
|
||||
and b.del_flag = '0'
|
||||
and c.del_flag = '0'
|
||||
and a.node_type in ('1','3','4')
|
||||
) t
|
||||
${ew.getCustomSqlSegment}
|
||||
</select>
|
||||
|
||||
<select id="getTaskCopyByPage" resultMap="FlowTaskResult">
|
||||
select * from (
|
||||
select
|
||||
b.id,
|
||||
b.update_time,
|
||||
c.business_id,
|
||||
c.flow_status,
|
||||
c.create_by,
|
||||
a.processed_by,
|
||||
a.create_time,
|
||||
b.form_custom,
|
||||
b.form_path,
|
||||
b.node_name,
|
||||
b.node_code,
|
||||
d.flow_name,
|
||||
d.flow_code,
|
||||
d.category,
|
||||
d.version
|
||||
from flow_user a
|
||||
left join flow_his_task b on a.associated = b.task_id
|
||||
left join flow_instance c on b.instance_id = c.id
|
||||
left join flow_definition d on c.definition_id=d.id
|
||||
where a.type = '4'
|
||||
and a.del_flag = '0'
|
||||
and b.del_flag = '0'
|
||||
and d.del_flag = '0'
|
||||
) t
|
||||
${ew.getCustomSqlSegment}
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.dromara.workflow.mapper.TestLeaveMapper">
|
||||
|
||||
</mapper>
|
Reference in New Issue
Block a user