refactor(flowable): 移除自定义流程图配置和相关工具类
- 删除 application.yml 中的 Flowable 配置项 - 移除 CustomProcessDiagramCanvas 自定义流程图绘制类 - 移除 CustomProcessDiagramGenerator 自定义流程图生成器 - 移除 FindNextNodeUtil 流程节点查找工具类 - 移除 FlowableConfig 配置类
This commit is contained in:
@@ -78,12 +78,6 @@
|
||||
<artifactId>klp-demo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- flowable模块-->
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-flowable</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- wms模块-->
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
package com.klp.web.controller.workflow;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.workflow.domain.WfCategory;
|
||||
import com.klp.workflow.domain.vo.WfCategoryVo;
|
||||
import com.klp.workflow.service.IWfCategoryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程分类Controller
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/category")
|
||||
public class WfCategoryController extends BaseController {
|
||||
|
||||
private final IWfCategoryService categoryService;
|
||||
|
||||
/**
|
||||
* 查询流程分类列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<WfCategoryVo> list(WfCategory category, PageQuery pageQuery) {
|
||||
return categoryService.queryPageList(category, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部的流程分类列表
|
||||
*/
|
||||
@SaCheckLogin
|
||||
@GetMapping("/listAll")
|
||||
public R<List<WfCategoryVo>> listAll(WfCategory category) {
|
||||
return R.ok(categoryService.queryList(category));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出流程分类列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:export")
|
||||
@Log(title = "流程分类", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Validated WfCategory category, HttpServletResponse response) {
|
||||
List<WfCategoryVo> list = categoryService.queryList(category);
|
||||
ExcelUtil.exportExcel(list, "流程分类", WfCategoryVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程分类详细信息
|
||||
* @param categoryId 分类主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:query")
|
||||
@GetMapping("/{categoryId}")
|
||||
public R<WfCategoryVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable("categoryId") Long categoryId) {
|
||||
return R.ok(categoryService.queryById(categoryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程分类
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:add")
|
||||
@Log(title = "流程分类", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated @RequestBody WfCategory category) {
|
||||
if (!categoryService.checkCategoryCodeUnique(category)) {
|
||||
return R.fail("新增流程分类'" + category.getCategoryName() + "'失败,流程编码已存在");
|
||||
}
|
||||
return toAjax(categoryService.insertCategory(category));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改流程分类
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:edit")
|
||||
@Log(title = "流程分类", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated @RequestBody WfCategory category) {
|
||||
if (!categoryService.checkCategoryCodeUnique(category)) {
|
||||
return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程编码已存在");
|
||||
}
|
||||
return toAjax(categoryService.updateCategory(category));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程分类
|
||||
* @param categoryIds 分类主键串
|
||||
*/
|
||||
@SaCheckPermission("workflow:category:remove")
|
||||
@Log(title = "流程分类" , businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{categoryIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] categoryIds) {
|
||||
return toAjax(categoryService.deleteWithValidByIds(Arrays.asList(categoryIds), true));
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package com.klp.web.controller.workflow;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.JsonUtils;
|
||||
import com.klp.flowable.core.domain.ProcessQuery;
|
||||
import com.klp.workflow.domain.vo.WfDeployVo;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import com.klp.workflow.service.IWfDeployFormService;
|
||||
import com.klp.workflow.service.IWfDeployService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 流程部署
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/24 20:57
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/deploy")
|
||||
public class WfDeployController extends BaseController {
|
||||
|
||||
private final IWfDeployService deployService;
|
||||
private final IWfDeployFormService deployFormService;
|
||||
|
||||
/**
|
||||
* 查询流程部署列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:deploy:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<WfDeployVo> list(ProcessQuery processQuery, PageQuery pageQuery) {
|
||||
return deployService.queryPageList(processQuery, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程部署版本列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:deploy:list")
|
||||
@GetMapping("/publishList")
|
||||
public TableDataInfo<WfDeployVo> publishList(@RequestParam String processKey, PageQuery pageQuery) {
|
||||
return deployService.queryPublishList(processKey, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活或挂起流程
|
||||
*
|
||||
* @param state 状态(active:激活 suspended:挂起)
|
||||
* @param definitionId 流程定义ID
|
||||
*/
|
||||
@SaCheckPermission("workflow:deploy:state")
|
||||
@PutMapping(value = "/changeState")
|
||||
public R<Void> changeState(@RequestParam String state, @RequestParam String definitionId) {
|
||||
deployService.updateState(definitionId, state);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取xml文件
|
||||
* @param definitionId 流程定义ID
|
||||
* @return
|
||||
*/
|
||||
@SaCheckPermission("workflow:deploy:query")
|
||||
@GetMapping("/bpmnXml/{definitionId}")
|
||||
public R<String> getBpmnXml(@PathVariable(value = "definitionId") String definitionId) {
|
||||
return R.ok(null, deployService.queryBpmnXmlById(definitionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程模型
|
||||
* @param deployIds 流程部署ids
|
||||
*/
|
||||
@SaCheckPermission("workflow:deploy:remove")
|
||||
@Log(title = "删除流程部署", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{deployIds}")
|
||||
public R<String> remove(@NotEmpty(message = "主键不能为空") @PathVariable String[] deployIds) {
|
||||
deployService.deleteByIds(Arrays.asList(deployIds));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程部署关联表单信息
|
||||
*
|
||||
* @param deployId 流程部署id
|
||||
*/
|
||||
@GetMapping("/form/{deployId}")
|
||||
public R<?> start(@PathVariable(value = "deployId") String deployId) {
|
||||
WfFormVo formVo = deployFormService.selectDeployFormByDeployId(deployId);
|
||||
if (Objects.isNull(formVo)) {
|
||||
return R.fail("请先配置流程表单");
|
||||
}
|
||||
return R.ok(JsonUtils.parseObject(formVo.getContent(), Map.class));
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package com.klp.web.controller.workflow;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.QueryGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.workflow.domain.WfDeployForm;
|
||||
import com.klp.workflow.domain.bo.WfFormBo;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import com.klp.workflow.service.IWfDeployFormService;
|
||||
import com.klp.workflow.service.IWfFormService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程表单Controller
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/form")
|
||||
public class WfFormController extends BaseController {
|
||||
|
||||
private final IWfFormService formService;
|
||||
|
||||
private final IWfDeployFormService deployFormService;
|
||||
|
||||
/**
|
||||
* 查询流程表单列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:form:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<WfFormVo> list(@Validated(QueryGroup.class) WfFormBo bo, PageQuery pageQuery) {
|
||||
return formService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出流程表单列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:form:export")
|
||||
@Log(title = "流程表单", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Validated WfFormBo bo, HttpServletResponse response) {
|
||||
List<WfFormVo> list = formService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "流程表单", WfFormVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程表单详细信息
|
||||
* @param formId 主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:form:query")
|
||||
@GetMapping(value = "/{formId}")
|
||||
public R<WfFormVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable("formId") Long formId) {
|
||||
return R.ok(formService.queryById(formId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程表单
|
||||
*/
|
||||
@SaCheckPermission("workflow:form:add")
|
||||
@Log(title = "流程表单", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public R<Void> add(@RequestBody WfFormBo bo) {
|
||||
return toAjax(formService.insertForm(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改流程表单
|
||||
*/
|
||||
@SaCheckPermission("workflow:form:edit")
|
||||
@Log(title = "流程表单", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public R<Void> edit(@RequestBody WfFormBo bo) {
|
||||
return toAjax(formService.updateForm(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程表单
|
||||
* @param formIds 主键串
|
||||
*/
|
||||
@SaCheckPermission("workflow:form:remove")
|
||||
@Log(title = "流程表单", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{formIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] formIds) {
|
||||
return toAjax(formService.deleteWithValidByIds(Arrays.asList(formIds)) ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 挂载流程表单
|
||||
*/
|
||||
@Log(title = "流程表单", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/addDeployForm")
|
||||
public R<Void> addDeployForm(@RequestBody WfDeployForm deployForm) {
|
||||
return toAjax(deployFormService.insertWfDeployForm(deployForm));
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.klp.web.controller.workflow;
|
||||
|
||||
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import com.klp.workflow.service.IWfInstanceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 工作流流程实例管理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/instance")
|
||||
public class WfInstanceController {
|
||||
|
||||
private final IWfInstanceService instanceService;
|
||||
|
||||
/**
|
||||
* 激活或挂起流程实例
|
||||
*
|
||||
* @param state 1:激活,2:挂起
|
||||
* @param instanceId 流程实例ID
|
||||
*/
|
||||
@PostMapping(value = "/updateState")
|
||||
public R updateState(@RequestParam Integer state, @RequestParam String instanceId) {
|
||||
instanceService.updateState(state, instanceId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束流程实例
|
||||
*
|
||||
* @param bo 流程任务业务对象
|
||||
*/
|
||||
@PostMapping(value = "/stopProcessInstance")
|
||||
public R stopProcessInstance(@RequestBody WfTaskBo bo) {
|
||||
instanceService.stopProcessInstance(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程实例
|
||||
*
|
||||
* @param instanceId 流程实例ID
|
||||
* @param deleteReason 删除原因
|
||||
*/
|
||||
@Deprecated
|
||||
@DeleteMapping(value = "/delete")
|
||||
public R delete(@RequestParam String instanceId, String deleteReason) {
|
||||
instanceService.delete(instanceId, deleteReason);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程实例详情信息
|
||||
*
|
||||
* @param procInsId 流程实例ID
|
||||
* @param deployId 流程部署ID
|
||||
*/
|
||||
@GetMapping("/detail")
|
||||
public R detail(String procInsId, String deployId) {
|
||||
return R.ok(instanceService.queryDetailProcess(procInsId, deployId));
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
package com.klp.web.controller.workflow;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.workflow.domain.WfCategory;
|
||||
import com.klp.workflow.domain.bo.WfModelBo;
|
||||
import com.klp.workflow.domain.vo.WfCategoryVo;
|
||||
import com.klp.workflow.domain.vo.WfModelExportVo;
|
||||
import com.klp.workflow.domain.vo.WfModelVo;
|
||||
import com.klp.workflow.service.IWfCategoryService;
|
||||
import com.klp.workflow.service.IWfModelService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 工作流流程模型管理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/21 9:09
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/model")
|
||||
public class WfModelController extends BaseController {
|
||||
|
||||
private final IWfModelService modelService;
|
||||
private final IWfCategoryService categoryService;
|
||||
|
||||
/**
|
||||
* 查询流程模型列表
|
||||
*
|
||||
* @param modelBo 流程模型对象
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<WfModelVo> list(WfModelBo modelBo, PageQuery pageQuery) {
|
||||
return modelService.list(modelBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程模型列表
|
||||
*
|
||||
* @param modelBo 流程模型对象
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:list")
|
||||
@GetMapping("/historyList")
|
||||
public TableDataInfo<WfModelVo> historyList(WfModelBo modelBo, PageQuery pageQuery) {
|
||||
return modelService.historyList(modelBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程模型详细信息
|
||||
*
|
||||
* @param modelId 模型主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:query")
|
||||
@GetMapping(value = "/{modelId}")
|
||||
public R<WfModelVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable("modelId") String modelId) {
|
||||
return R.ok(modelService.getModel(modelId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程表单详细信息
|
||||
*
|
||||
* @param modelId 模型主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:query")
|
||||
@GetMapping(value = "/bpmnXml/{modelId}")
|
||||
public R<String> getBpmnXml(@NotNull(message = "主键不能为空") @PathVariable("modelId") String modelId) {
|
||||
return R.ok("操作成功", modelService.queryBpmnXmlById(modelId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程模型
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:add")
|
||||
@Log(title = "流程模型", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody WfModelBo modelBo) {
|
||||
modelService.insertModel(modelBo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改流程模型
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:edit")
|
||||
@Log(title = "流程模型", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody WfModelBo modelBo) {
|
||||
modelService.updateModel(modelBo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存流程模型
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:save")
|
||||
@Log(title = "保存流程模型", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/save")
|
||||
public R<String> save(@RequestBody WfModelBo modelBo) {
|
||||
modelService.saveModel(modelBo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设为最新流程模型
|
||||
* @param modelId
|
||||
* @return
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:save")
|
||||
@Log(title = "设为最新流程模型", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/latest")
|
||||
public R<?> latest(@RequestParam String modelId) {
|
||||
modelService.latestModel(modelId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程模型
|
||||
*
|
||||
* @param modelIds 流程模型主键串
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:remove")
|
||||
@Log(title = "删除流程模型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{modelIds}")
|
||||
public R<String> remove(@NotEmpty(message = "主键不能为空") @PathVariable String[] modelIds) {
|
||||
modelService.deleteByIds(Arrays.asList(modelIds));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署流程模型
|
||||
*
|
||||
* @param modelId 流程模型主键
|
||||
*/
|
||||
@SaCheckPermission("workflow:model:deploy")
|
||||
@Log(title = "部署流程模型", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/deploy")
|
||||
public R<Void> deployModel(@RequestParam String modelId) {
|
||||
return toAjax(modelService.deployModel(modelId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出流程模型数据
|
||||
*/
|
||||
@Log(title = "导出流程模型数据", businessType = BusinessType.EXPORT)
|
||||
@SaCheckPermission("workflow:model:export")
|
||||
@PostMapping("/export")
|
||||
public void export(WfModelBo modelBo, HttpServletResponse response) {
|
||||
List<WfModelVo> list = modelService.list(modelBo);
|
||||
List<WfModelExportVo> listVo = BeanUtil.copyToList(list, WfModelExportVo.class);
|
||||
List<WfCategoryVo> categoryVos = categoryService.queryList(new WfCategory());
|
||||
Map<String, String> categoryMap = categoryVos.stream()
|
||||
.collect(Collectors.toMap(WfCategoryVo::getCode, WfCategoryVo::getCategoryName));
|
||||
for (WfModelExportVo exportVo : listVo) {
|
||||
exportVo.setCategoryName(categoryMap.get(exportVo.getCategory()));
|
||||
}
|
||||
ExcelUtil.exportExcel(listVo, "流程模型数据", WfModelExportVo.class, response);
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
package com.klp.web.controller.workflow;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.flowable.core.domain.ProcessQuery;
|
||||
import com.klp.workflow.domain.bo.WfCopyBo;
|
||||
import com.klp.workflow.domain.vo.*;
|
||||
import com.klp.workflow.service.IWfCopyService;
|
||||
import com.klp.workflow.service.IWfProcessService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流流程管理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/24 18:54
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/process")
|
||||
public class WfProcessController extends BaseController {
|
||||
|
||||
private final IWfProcessService processService;
|
||||
private final IWfCopyService copyService;
|
||||
|
||||
/**
|
||||
* 查询可发起流程列表
|
||||
*
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
@GetMapping(value = "/list")
|
||||
@SaCheckPermission("workflow:process:startList")
|
||||
public TableDataInfo<WfDefinitionVo> startProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
|
||||
return processService.selectPageStartProcessList(processQuery, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 我拥有的流程
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:ownList")
|
||||
@GetMapping(value = "/ownList")
|
||||
public TableDataInfo<WfTaskVo> ownProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
|
||||
return processService.selectPageOwnProcessList(processQuery, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待办列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:todoList")
|
||||
@GetMapping(value = "/todoList")
|
||||
public TableDataInfo<WfTaskVo> todoProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
|
||||
return processService.selectPageTodoProcessList(processQuery, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待签列表
|
||||
*
|
||||
* @param processQuery 流程业务对象
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:claimList")
|
||||
@GetMapping(value = "/claimList")
|
||||
public TableDataInfo<WfTaskVo> claimProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
|
||||
return processService.selectPageClaimProcessList(processQuery, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已办列表
|
||||
*
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:finishedList")
|
||||
@GetMapping(value = "/finishedList")
|
||||
public TableDataInfo<WfTaskVo> finishedProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
|
||||
return processService.selectPageFinishedProcessList(processQuery, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取抄送列表
|
||||
*
|
||||
* @param copyBo 流程抄送对象
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:copyList")
|
||||
@GetMapping(value = "/copyList")
|
||||
public TableDataInfo<WfCopyVo> copyProcessList(WfCopyBo copyBo, PageQuery pageQuery) {
|
||||
copyBo.setUserId(getUserId());
|
||||
return copyService.selectPageList(copyBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出可发起流程列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:startExport")
|
||||
@Log(title = "可发起流程", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/startExport")
|
||||
public void startExport(@Validated ProcessQuery processQuery, HttpServletResponse response) {
|
||||
List<WfDefinitionVo> list = processService.selectStartProcessList(processQuery);
|
||||
ExcelUtil.exportExcel(list, "可发起流程", WfDefinitionVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出我拥有流程列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:ownExport")
|
||||
@Log(title = "我拥有流程", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/ownExport")
|
||||
public void ownExport(@Validated ProcessQuery processQuery, HttpServletResponse response) {
|
||||
List<WfTaskVo> list = processService.selectOwnProcessList(processQuery);
|
||||
List<WfOwnTaskExportVo> listVo = BeanUtil.copyToList(list, WfOwnTaskExportVo.class);
|
||||
for (WfOwnTaskExportVo exportVo : listVo) {
|
||||
exportVo.setStatus(ObjectUtil.isNull(exportVo.getFinishTime()) ? "进行中" : "已完成");
|
||||
}
|
||||
ExcelUtil.exportExcel(listVo, "我拥有流程", WfOwnTaskExportVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出待办流程列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:todoExport")
|
||||
@Log(title = "待办流程", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/todoExport")
|
||||
public void todoExport(@Validated ProcessQuery processQuery, HttpServletResponse response) {
|
||||
List<WfTaskVo> list = processService.selectTodoProcessList(processQuery);
|
||||
List<WfTodoTaskExportVo> listVo = BeanUtil.copyToList(list, WfTodoTaskExportVo.class);
|
||||
ExcelUtil.exportExcel(listVo, "待办流程", WfTodoTaskExportVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出待签流程列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:claimExport")
|
||||
@Log(title = "待签流程", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/claimExport")
|
||||
public void claimExport(@Validated ProcessQuery processQuery, HttpServletResponse response) {
|
||||
List<WfTaskVo> list = processService.selectClaimProcessList(processQuery);
|
||||
List<WfClaimTaskExportVo> listVo = BeanUtil.copyToList(list, WfClaimTaskExportVo.class);
|
||||
ExcelUtil.exportExcel(listVo, "待签流程", WfClaimTaskExportVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出已办流程列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:finishedExport")
|
||||
@Log(title = "已办流程", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/finishedExport")
|
||||
public void finishedExport(@Validated ProcessQuery processQuery, HttpServletResponse response) {
|
||||
List<WfTaskVo> list = processService.selectFinishedProcessList(processQuery);
|
||||
List<WfFinishedTaskExportVo> listVo = BeanUtil.copyToList(list, WfFinishedTaskExportVo.class);
|
||||
ExcelUtil.exportExcel(listVo, "已办流程", WfFinishedTaskExportVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出抄送流程列表
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:copyExport")
|
||||
@Log(title = "抄送流程", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/copyExport")
|
||||
public void copyExport(WfCopyBo copyBo, HttpServletResponse response) {
|
||||
copyBo.setUserId(getUserId());
|
||||
List<WfCopyVo> list = copyService.selectList(copyBo);
|
||||
ExcelUtil.exportExcel(list, "抄送流程", WfCopyVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程部署关联表单信息
|
||||
*
|
||||
* @param definitionId 流程定义id
|
||||
* @param deployId 流程部署id
|
||||
*/
|
||||
@GetMapping("/getProcessForm")
|
||||
@SaCheckPermission("workflow:process:start")
|
||||
public R<?> getForm(@RequestParam(value = "definitionId") String definitionId,
|
||||
@RequestParam(value = "deployId") String deployId,
|
||||
@RequestParam(value = "procInsId", required = false) String procInsId) {
|
||||
return R.ok(processService.selectFormContent(definitionId, deployId, procInsId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流程定义id启动流程实例
|
||||
*
|
||||
* @param processDefId 流程定义id
|
||||
* @param variables 变量集合,json对象
|
||||
*/
|
||||
@SaCheckPermission("workflow:process:start")
|
||||
@PostMapping("/start/{processDefId}")
|
||||
public R<Void> start(@PathVariable(value = "processDefId") String processDefId, @RequestBody Map<String, Object> variables) {
|
||||
// 如果包含审批人信息,则处理审批人信息
|
||||
processService.startProcessByDefId(processDefId, variables);
|
||||
return R.ok("流程启动成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程实例
|
||||
*
|
||||
* @param instanceIds 流程实例ID串
|
||||
*/
|
||||
@DeleteMapping("/instance/{instanceIds}")
|
||||
public R<Void> delete(@PathVariable String[] instanceIds) {
|
||||
processService.deleteProcessByIds(instanceIds);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取xml文件
|
||||
* @param processDefId 流程定义ID
|
||||
*/
|
||||
@GetMapping("/bpmnXml/{processDefId}")
|
||||
public R<String> getBpmnXml(@PathVariable(value = "processDefId") String processDefId) {
|
||||
return R.ok(null, processService.queryBpmnXmlById(processDefId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程详情信息
|
||||
*
|
||||
* @param procInsId 流程实例ID
|
||||
* @param taskId 任务ID
|
||||
*/
|
||||
@GetMapping("/detail")
|
||||
public R detail(String procInsId, String taskId) {
|
||||
return R.ok(processService.queryProcessDetail(procInsId, taskId));
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
package com.klp.web.controller.workflow;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import com.klp.workflow.service.IWfTaskService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* 工作流任务管理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/workflow/task")
|
||||
public class WfTaskController {
|
||||
|
||||
private final IWfTaskService flowTaskService;
|
||||
|
||||
/**
|
||||
* 取消流程
|
||||
*/
|
||||
@PostMapping(value = "/stopProcess")
|
||||
@SaCheckPermission("workflow:process:cancel")
|
||||
public R stopProcess(@RequestBody WfTaskBo bo) {
|
||||
flowTaskService.stopProcess(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回流程
|
||||
*/
|
||||
@PostMapping(value = "/revokeProcess")
|
||||
@SaCheckPermission("workflow:process:revoke")
|
||||
public R revokeProcess(@RequestBody WfTaskBo bo) {
|
||||
flowTaskService.revokeProcess(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程变量
|
||||
* @param taskId 流程任务Id
|
||||
*/
|
||||
@GetMapping(value = "/processVariables/{taskId}")
|
||||
@SaCheckPermission("workflow:process:query")
|
||||
public R processVariables(@PathVariable(value = "taskId") String taskId) {
|
||||
return R.ok(flowTaskService.getProcessVariables(taskId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批任务
|
||||
*/
|
||||
@PostMapping(value = "/complete")
|
||||
@SaCheckPermission("workflow:process:approval")
|
||||
public R complete(@RequestBody WfTaskBo bo) {
|
||||
flowTaskService.complete(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝任务
|
||||
*/
|
||||
@PostMapping(value = "/reject")
|
||||
@SaCheckPermission("workflow:process:approval")
|
||||
public R taskReject(@RequestBody WfTaskBo taskBo) {
|
||||
flowTaskService.taskReject(taskBo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 退回任务
|
||||
*/
|
||||
@PostMapping(value = "/return")
|
||||
@SaCheckPermission("workflow:process:approval")
|
||||
public R taskReturn(@RequestBody WfTaskBo bo) {
|
||||
flowTaskService.taskReturn(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有可回退的节点
|
||||
*/
|
||||
@PostMapping(value = "/returnList")
|
||||
@SaCheckPermission("workflow:process:query")
|
||||
public R findReturnTaskList(@RequestBody WfTaskBo bo) {
|
||||
return R.ok(flowTaskService.findReturnTaskList(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*/
|
||||
@DeleteMapping(value = "/delete")
|
||||
@SaCheckPermission("workflow:process:approval")
|
||||
public R delete(@RequestBody WfTaskBo bo) {
|
||||
flowTaskService.deleteTask(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 认领/签收任务
|
||||
*/
|
||||
@PostMapping(value = "/claim")
|
||||
@SaCheckPermission("workflow:process:claim")
|
||||
public R claim(@RequestBody WfTaskBo bo) {
|
||||
flowTaskService.claim(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消认领/签收任务
|
||||
*/
|
||||
@PostMapping(value = "/unClaim")
|
||||
@SaCheckPermission("workflow:process:claim")
|
||||
public R unClaim(@RequestBody WfTaskBo bo) {
|
||||
flowTaskService.unClaim(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 委派任务
|
||||
*/
|
||||
@PostMapping(value = "/delegate")
|
||||
@SaCheckPermission("workflow:process:approval")
|
||||
public R delegate(@RequestBody WfTaskBo bo) {
|
||||
if (ObjectUtil.hasNull(bo.getTaskId(), bo.getUserId())) {
|
||||
return R.fail("参数错误!");
|
||||
}
|
||||
flowTaskService.delegateTask(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转办任务
|
||||
*/
|
||||
@PostMapping(value = "/transfer")
|
||||
@SaCheckPermission("workflow:process:approval")
|
||||
public R transfer(@RequestBody WfTaskBo bo) {
|
||||
if (ObjectUtil.hasNull(bo.getTaskId(), bo.getUserId())) {
|
||||
return R.fail("参数错误!");
|
||||
}
|
||||
flowTaskService.transferTask(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成流程图
|
||||
*
|
||||
* @param processId 任务ID
|
||||
*/
|
||||
@RequestMapping("/diagram/{processId}")
|
||||
public void genProcessDiagram(HttpServletResponse response,
|
||||
@PathVariable("processId") String processId) {
|
||||
InputStream inputStream = flowTaskService.diagram(processId);
|
||||
OutputStream os = null;
|
||||
BufferedImage image = null;
|
||||
try {
|
||||
image = ImageIO.read(inputStream);
|
||||
response.setContentType("image/png");
|
||||
os = response.getOutputStream();
|
||||
if (image != null) {
|
||||
ImageIO.write(image, "png", os);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (os != null) {
|
||||
os.flush();
|
||||
os.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,19 +298,6 @@ management:
|
||||
logfile:
|
||||
external-file: ./logs/sys-console.log
|
||||
|
||||
--- # Flowable 配置
|
||||
flowable:
|
||||
# 关闭定时任务 job
|
||||
async-executor-activate: false
|
||||
# 库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
|
||||
database-schema-update: true
|
||||
idm:
|
||||
# 关闭idm引擎 数据库不会创建act_id_*表,流程流转不会使用act_id_*相关的表
|
||||
enabled: false
|
||||
# 关闭流程定义文件自动检查
|
||||
check-process-definitions: false
|
||||
# 关闭历史任务定时任务job
|
||||
async-history-executor-activate: false
|
||||
|
||||
# 图像识别 OCR 配置(语言包绝对路径)
|
||||
tesseract:
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>klp-oa</artifactId>
|
||||
<groupId>com.klp</groupId>
|
||||
<version>0.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>klp-flowable</artifactId>
|
||||
|
||||
<description>
|
||||
flowable工作流
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.flowable</groupId>
|
||||
<artifactId>flowable-spring-boot-starter-process</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.googlecode.aviator</groupId>
|
||||
<artifactId>aviator</artifactId>
|
||||
<version>5.3.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,82 +0,0 @@
|
||||
package com.klp.flowable.common.constant;
|
||||
|
||||
/**
|
||||
* 流程常量信息
|
||||
*
|
||||
* @author Xuan xuan
|
||||
* @date 2021/4/17 22:46
|
||||
*/
|
||||
public class ProcessConstants {
|
||||
|
||||
public static final String SUFFIX = ".bpmn";
|
||||
|
||||
/**
|
||||
* 动态数据
|
||||
*/
|
||||
public static final String DATA_TYPE = "dynamic";
|
||||
|
||||
/**
|
||||
* 单个审批人
|
||||
*/
|
||||
public static final String USER_TYPE_ASSIGNEE = "assignee";
|
||||
|
||||
|
||||
/**
|
||||
* 候选人
|
||||
*/
|
||||
public static final String USER_TYPE_USERS = "candidateUsers";
|
||||
|
||||
|
||||
/**
|
||||
* 审批组
|
||||
*/
|
||||
public static final String USER_TYPE_ROUPS = "candidateGroups";
|
||||
|
||||
/**
|
||||
* 单个审批人
|
||||
*/
|
||||
public static final String PROCESS_APPROVAL = "approval";
|
||||
|
||||
/**
|
||||
* 会签人员
|
||||
*/
|
||||
public static final String PROCESS_MULTI_INSTANCE_USER = "userList";
|
||||
|
||||
/**
|
||||
* nameapace
|
||||
*/
|
||||
public static final String NAMASPASE = "http://flowable.org/bpmn";
|
||||
|
||||
/**
|
||||
* 会签节点
|
||||
*/
|
||||
public static final String PROCESS_MULTI_INSTANCE = "multiInstance";
|
||||
|
||||
/**
|
||||
* 自定义属性 dataType
|
||||
*/
|
||||
public static final String PROCESS_CUSTOM_DATA_TYPE = "dataType";
|
||||
|
||||
/**
|
||||
* 自定义属性 userType
|
||||
*/
|
||||
public static final String PROCESS_CUSTOM_USER_TYPE = "userType";
|
||||
|
||||
/**
|
||||
* 自定义属性 localScope
|
||||
*/
|
||||
public static final String PROCESS_FORM_LOCAL_SCOPE = "localScope";
|
||||
|
||||
/**
|
||||
* 自定义属性 流程状态
|
||||
*/
|
||||
public static final String PROCESS_STATUS_KEY = "processStatus";
|
||||
|
||||
|
||||
/**
|
||||
* 流程跳过
|
||||
*/
|
||||
public static final String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED";
|
||||
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.klp.flowable.common.constant;
|
||||
|
||||
/**
|
||||
* @author konbai
|
||||
* @createTime 2022/4/24 13:24
|
||||
*/
|
||||
public class TaskConstants {
|
||||
|
||||
/**
|
||||
* 流程发起人
|
||||
*/
|
||||
public static final String PROCESS_INITIATOR = "initiator";
|
||||
|
||||
/**
|
||||
* 角色候选组前缀
|
||||
*/
|
||||
public static final String ROLE_GROUP_PREFIX = "ROLE";
|
||||
|
||||
/**
|
||||
* 部门候选组前缀
|
||||
*/
|
||||
public static final String DEPT_GROUP_PREFIX = "DEPT";
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.klp.flowable.common.enums;
|
||||
|
||||
/**
|
||||
* 流程意见类型
|
||||
*
|
||||
* @author Xuan xuan
|
||||
* @date 2021/4/19
|
||||
*/
|
||||
public enum FlowComment {
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
NORMAL("1", "正常"),
|
||||
REBACK("2", "退回"),
|
||||
REJECT("3", "驳回"),
|
||||
DELEGATE("4", "委派"),
|
||||
TRANSFER("5", "转办"),
|
||||
STOP("6", "终止"),
|
||||
REVOKE("7", "撤回");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String remark;
|
||||
|
||||
FlowComment(String type, String remark) {
|
||||
this.type = type;
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.klp.flowable.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/28 9:51
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum FormType {
|
||||
|
||||
/**
|
||||
* 流程表单
|
||||
*/
|
||||
PROCESS(0),
|
||||
|
||||
/**
|
||||
* 外置表单
|
||||
*/
|
||||
EXTERNAL(1),
|
||||
|
||||
/**
|
||||
* 节点独立表单
|
||||
*/
|
||||
INDEPENDENT(2);
|
||||
|
||||
/**
|
||||
* 表单类型
|
||||
*/
|
||||
private final Integer type;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.klp.flowable.common.enums;
|
||||
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author konbai
|
||||
* @since 2023/3/9 00:45
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ProcessStatus {
|
||||
|
||||
/**
|
||||
* 进行中(审批中)
|
||||
*/
|
||||
RUNNING("running"),
|
||||
/**
|
||||
* 已终止
|
||||
*/
|
||||
TERMINATED("terminated"),
|
||||
/**
|
||||
* 已完成
|
||||
*/
|
||||
COMPLETED("completed"),
|
||||
/**
|
||||
* 已取消
|
||||
*/
|
||||
CANCELED("canceled");
|
||||
|
||||
private final String status;
|
||||
|
||||
public static ProcessStatus getProcessStatus(String str) {
|
||||
if (StringUtils.isNotBlank(str)) {
|
||||
for (ProcessStatus value : values()) {
|
||||
if (StringUtils.equalsIgnoreCase(str, value.getStatus())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.klp.flowable.config;
|
||||
|
||||
import com.klp.flowable.listener.GlobalEventListener;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
|
||||
/**
|
||||
* flowable全局监听配置
|
||||
*
|
||||
* @author ssc
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
public class GlobalEventListenerConfig implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private final GlobalEventListener globalEventListener;
|
||||
private final RuntimeService runtimeService;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
// 流程正常结束
|
||||
runtimeService.addEventListener(globalEventListener, FlowableEngineEventType.PROCESS_COMPLETED);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package com.klp.flowable.config;
|
||||
|
||||
import org.flowable.bpmn.model.AssociationDirection;
|
||||
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
/**
|
||||
* @author XuanXuan
|
||||
* @date 2021-04-03
|
||||
*/
|
||||
public class MyDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
|
||||
//设置高亮线的颜色 这里我设置成绿色
|
||||
protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;
|
||||
|
||||
public MyDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
|
||||
super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
|
||||
}
|
||||
|
||||
public MyDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
|
||||
super(width, height, minX, minY, imageType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 画线颜色设置
|
||||
*/
|
||||
@Override
|
||||
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
|
||||
AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
|
||||
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
|
||||
g.setPaint(CONNECTION_COLOR);
|
||||
if (connectionType.equals("association")) {
|
||||
g.setStroke(ASSOCIATION_STROKE);
|
||||
} else if (highLighted) {
|
||||
//设置线的颜色
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(HIGHLIGHT_FLOW_STROKE);
|
||||
}
|
||||
|
||||
for (int i = 1; i < xPoints.length; i++) {
|
||||
Integer sourceX = xPoints[i - 1];
|
||||
Integer sourceY = yPoints[i - 1];
|
||||
Integer targetX = xPoints[i];
|
||||
Integer targetY = yPoints[i];
|
||||
Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
|
||||
g.draw(line);
|
||||
}
|
||||
|
||||
if (isDefault) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
||||
drawDefaultSequenceFlowIndicator(line, scaleFactor);
|
||||
}
|
||||
|
||||
if (conditional) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
||||
drawConditionalSequenceFlowIndicator(line, scaleFactor);
|
||||
}
|
||||
|
||||
if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
|
||||
drawArrowHead(line, scaleFactor);
|
||||
}
|
||||
if (associationDirection == AssociationDirection.BOTH) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
|
||||
drawArrowHead(line, scaleFactor);
|
||||
}
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(originalStroke);
|
||||
}
|
||||
|
||||
/**
|
||||
* 高亮节点设置
|
||||
*/
|
||||
@Override
|
||||
public void drawHighLight(int x, int y, int width, int height) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
//设置高亮节点的颜色
|
||||
g.setPaint(HIGHLIGHT_COLOR);
|
||||
g.setStroke(THICK_TASK_BORDER_STROKE);
|
||||
|
||||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
|
||||
g.draw(rect);
|
||||
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(originalStroke);
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.klp.flowable.core;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 表单属性类
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/8/6 18:54
|
||||
*/
|
||||
@Data
|
||||
public class FormConf {
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 表单名
|
||||
*/
|
||||
private String formRef;
|
||||
/**
|
||||
* 表单模型
|
||||
*/
|
||||
private String formModel;
|
||||
/**
|
||||
* 表单尺寸
|
||||
*/
|
||||
private String size;
|
||||
/**
|
||||
* 标签对齐
|
||||
*/
|
||||
private String labelPosition;
|
||||
/**
|
||||
* 标签宽度
|
||||
*/
|
||||
private Integer labelWidth;
|
||||
/**
|
||||
* 校验模型
|
||||
*/
|
||||
private String formRules;
|
||||
/**
|
||||
* 栅格间隔
|
||||
*/
|
||||
private Integer gutter;
|
||||
/**
|
||||
* 禁用表单
|
||||
*/
|
||||
private Boolean disabled = false;
|
||||
/**
|
||||
* 栅格占据的列数
|
||||
*/
|
||||
private Integer span;
|
||||
/**
|
||||
* 表单按钮
|
||||
*/
|
||||
private Boolean formBtns = true;
|
||||
/**
|
||||
* 表单项
|
||||
*/
|
||||
private List<Map<String, Object>> fields;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.klp.flowable.core.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程查询实体对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/11 01:15
|
||||
*/
|
||||
@Data
|
||||
public class ProcessQuery {
|
||||
|
||||
/**
|
||||
* 流程标识
|
||||
*/
|
||||
private String processKey;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程分类
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.klp.flowable.factory;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.flowable.engine.*;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* flowable 引擎注入封装
|
||||
* @author XuanXuan
|
||||
* @date 2021-04-03
|
||||
*/
|
||||
@Component
|
||||
@Getter
|
||||
public class FlowServiceFactory {
|
||||
|
||||
@Resource
|
||||
protected RepositoryService repositoryService;
|
||||
|
||||
@Resource
|
||||
protected RuntimeService runtimeService;
|
||||
|
||||
@Resource
|
||||
protected IdentityService identityService;
|
||||
|
||||
@Resource
|
||||
protected TaskService taskService;
|
||||
|
||||
@Resource
|
||||
protected FormService formService;
|
||||
|
||||
@Resource
|
||||
protected HistoryService historyService;
|
||||
|
||||
@Resource
|
||||
protected ManagementService managementService;
|
||||
|
||||
@Qualifier("processEngine")
|
||||
@Resource
|
||||
protected ProcessEngine processEngine;
|
||||
|
||||
}
|
||||
@@ -1,370 +0,0 @@
|
||||
package com.klp.flowable.flow;
|
||||
|
||||
import org.flowable.bpmn.model.AssociationDirection;
|
||||
import org.flowable.bpmn.model.GraphicInfo;
|
||||
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
|
||||
import org.flowable.image.util.ReflectUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.LineBreakMeasurer;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedString;
|
||||
|
||||
/**
|
||||
* @author XuanXuan
|
||||
* @date 2021/4/4 23:58
|
||||
*/
|
||||
public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
|
||||
//定义走过流程连线颜色为绿色
|
||||
protected static Color HIGHLIGHT_SequenceFlow_COLOR = Color.GREEN;
|
||||
//设置未走过流程的连接线颜色
|
||||
protected static Color CONNECTION_COLOR = Color.BLACK;
|
||||
//设置flows连接线字体颜色red
|
||||
protected static Color LABEL_COLOR = new Color(0, 0, 0);
|
||||
//高亮显示task框颜色
|
||||
protected static Color HIGHLIGHT_COLOR = Color.GREEN;
|
||||
protected static Color HIGHLIGHT_COLOR1 = Color.RED;
|
||||
|
||||
public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
|
||||
super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
|
||||
this.initialize(imageType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写绘制连线的方式,设置绘制颜色
|
||||
* @param xPoints
|
||||
* @param yPoints
|
||||
* @param conditional
|
||||
* @param isDefault
|
||||
* @param connectionType
|
||||
* @param associationDirection
|
||||
* @param highLighted
|
||||
* @param scaleFactor
|
||||
*/
|
||||
@Override
|
||||
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
|
||||
Paint originalPaint = this.g.getPaint();
|
||||
Stroke originalStroke = this.g.getStroke();
|
||||
this.g.setPaint(CONNECTION_COLOR);
|
||||
if (connectionType.equals("association")) {
|
||||
this.g.setStroke(ASSOCIATION_STROKE);
|
||||
} else if (highLighted) {
|
||||
this.g.setPaint(HIGHLIGHT_SequenceFlow_COLOR);
|
||||
this.g.setStroke(HIGHLIGHT_FLOW_STROKE);
|
||||
}
|
||||
|
||||
for (int i = 1; i < xPoints.length; ++i) {
|
||||
int sourceX = xPoints[i - 1];
|
||||
int sourceY = yPoints[i - 1];
|
||||
int targetX = xPoints[i];
|
||||
int targetY = yPoints[i];
|
||||
java.awt.geom.Line2D.Double line = new java.awt.geom.Line2D.Double((double) sourceX, (double) sourceY, (double) targetX, (double) targetY);
|
||||
this.g.draw(line);
|
||||
}
|
||||
|
||||
java.awt.geom.Line2D.Double line;
|
||||
if (isDefault) {
|
||||
line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]);
|
||||
this.drawDefaultSequenceFlowIndicator(line, scaleFactor);
|
||||
}
|
||||
|
||||
if (conditional) {
|
||||
line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]);
|
||||
this.drawConditionalSequenceFlowIndicator(line, scaleFactor);
|
||||
}
|
||||
|
||||
if (associationDirection.equals(AssociationDirection.ONE) || associationDirection.equals(AssociationDirection.BOTH)) {
|
||||
line = new java.awt.geom.Line2D.Double((double) xPoints[xPoints.length - 2], (double) yPoints[xPoints.length - 2], (double) xPoints[xPoints.length - 1], (double) yPoints[xPoints.length - 1]);
|
||||
this.drawArrowHead(line, scaleFactor);
|
||||
}
|
||||
|
||||
if (associationDirection.equals(AssociationDirection.BOTH)) {
|
||||
line = new java.awt.geom.Line2D.Double((double) xPoints[1], (double) yPoints[1], (double) xPoints[0], (double) yPoints[0]);
|
||||
this.drawArrowHead(line, scaleFactor);
|
||||
}
|
||||
|
||||
this.g.setPaint(originalPaint);
|
||||
this.g.setStroke(originalStroke);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体大小图标颜色
|
||||
* @param imageType
|
||||
*/
|
||||
@Override
|
||||
public void initialize(String imageType) {
|
||||
if ("png".equalsIgnoreCase(imageType)) {
|
||||
this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 2);
|
||||
} else {
|
||||
this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 1);
|
||||
}
|
||||
|
||||
this.g = this.processDiagram.createGraphics();
|
||||
if (!"png".equalsIgnoreCase(imageType)) {
|
||||
this.g.setBackground(new Color(255, 255, 255, 0));
|
||||
this.g.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
|
||||
}
|
||||
|
||||
this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
//修改图标颜色,修改图标字体大小
|
||||
this.g.setPaint(Color.black);
|
||||
Font font = new Font(this.activityFontName, 10, 14);
|
||||
this.g.setFont(font);
|
||||
this.fontMetrics = this.g.getFontMetrics();
|
||||
//修改连接线字体大小
|
||||
LABEL_FONT = new Font(this.labelFontName, 10, 15);
|
||||
ANNOTATION_FONT = new Font(this.annotationFontName, 0, 11);
|
||||
|
||||
try {
|
||||
USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/userTask.png", this.customClassLoader));
|
||||
SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/scriptTask.png", this.customClassLoader));
|
||||
SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/serviceTask.png", this.customClassLoader));
|
||||
RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/receiveTask.png", this.customClassLoader));
|
||||
SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/sendTask.png", this.customClassLoader));
|
||||
MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/manualTask.png", this.customClassLoader));
|
||||
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/businessRuleTask.png", this.customClassLoader));
|
||||
SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/shellTask.png", this.customClassLoader));
|
||||
DMN_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/dmnTask.png", this.customClassLoader));
|
||||
CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/camelTask.png", this.customClassLoader));
|
||||
MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/muleTask.png", this.customClassLoader));
|
||||
HTTP_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/httpTask.png", this.customClassLoader));
|
||||
TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/timer.png", this.customClassLoader));
|
||||
COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate-throw.png", this.customClassLoader));
|
||||
COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate.png", this.customClassLoader));
|
||||
ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error-throw.png", this.customClassLoader));
|
||||
ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error.png", this.customClassLoader));
|
||||
MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message-throw.png", this.customClassLoader));
|
||||
MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message.png", this.customClassLoader));
|
||||
SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal-throw.png", this.customClassLoader));
|
||||
SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal.png", this.customClassLoader));
|
||||
} catch (IOException var4) {
|
||||
LOGGER.warn("Could not load image for process diagram creation: {}", var4.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接线字体
|
||||
* @param text
|
||||
* @param graphicInfo
|
||||
* @param centered
|
||||
*/
|
||||
@Override
|
||||
public void drawLabel(String text, GraphicInfo graphicInfo, boolean centered) {
|
||||
float interline = 1.0f;
|
||||
|
||||
// text
|
||||
if (text != null && text.length() > 0) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Font originalFont = g.getFont();
|
||||
|
||||
g.setPaint(LABEL_COLOR);
|
||||
g.setFont(LABEL_FONT);
|
||||
|
||||
int wrapWidth = 100;
|
||||
int textY = (int) graphicInfo.getY();
|
||||
|
||||
// TODO: use drawMultilineText()
|
||||
AttributedString as = new AttributedString(text);
|
||||
as.addAttribute(TextAttribute.FOREGROUND, g.getPaint());
|
||||
as.addAttribute(TextAttribute.FONT, g.getFont());
|
||||
AttributedCharacterIterator aci = as.getIterator();
|
||||
FontRenderContext frc = new FontRenderContext(null, true, false);
|
||||
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
|
||||
|
||||
while (lbm.getPosition() < text.length()) {
|
||||
TextLayout tl = lbm.nextLayout(wrapWidth);
|
||||
textY += tl.getAscent();
|
||||
|
||||
Rectangle2D bb = tl.getBounds();
|
||||
double tX = graphicInfo.getX();
|
||||
|
||||
if (centered) {
|
||||
tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2);
|
||||
}
|
||||
tl.draw(g, (float) tX, textY);
|
||||
textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent();
|
||||
}
|
||||
|
||||
// restore originals
|
||||
g.setFont(originalFont);
|
||||
g.setPaint(originalPaint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 高亮显示task框完成的
|
||||
* @param x
|
||||
* @param y
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
@Override
|
||||
public void drawHighLight(int x, int y, int width, int height) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
|
||||
g.setPaint(HIGHLIGHT_COLOR);
|
||||
g.setStroke(THICK_TASK_BORDER_STROKE);
|
||||
|
||||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
|
||||
g.draw(rect);
|
||||
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(originalStroke);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义task框当前的位置
|
||||
* @param x
|
||||
* @param y
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
public void drawHighLightNow(int x, int y, int width, int height) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
|
||||
g.setPaint(HIGHLIGHT_COLOR1);
|
||||
g.setStroke(THICK_TASK_BORDER_STROKE);
|
||||
|
||||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
|
||||
g.draw(rect);
|
||||
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(originalStroke);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义结束节点
|
||||
* @param x
|
||||
* @param y
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
public void drawHighLightEnd(int x, int y, int width, int height) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
|
||||
g.setPaint(HIGHLIGHT_COLOR);
|
||||
g.setStroke(THICK_TASK_BORDER_STROKE);
|
||||
|
||||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
|
||||
g.draw(rect);
|
||||
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(originalStroke);
|
||||
}
|
||||
|
||||
/**
|
||||
* task框自定义文字
|
||||
* @param name
|
||||
* @param graphicInfo
|
||||
* @param thickBorder
|
||||
* @param scaleFactor
|
||||
*/
|
||||
@Override
|
||||
protected void drawTask(String name, GraphicInfo graphicInfo, boolean thickBorder, double scaleFactor) {
|
||||
|
||||
Paint originalPaint = g.getPaint();
|
||||
int x = (int) graphicInfo.getX();
|
||||
int y = (int) graphicInfo.getY();
|
||||
int width = (int) graphicInfo.getWidth();
|
||||
int height = (int) graphicInfo.getHeight();
|
||||
|
||||
// Create a new gradient paint for every task box, gradient depends on x and y and is not relative
|
||||
g.setPaint(TASK_BOX_COLOR);
|
||||
|
||||
int arcR = 6;
|
||||
if (thickBorder) {
|
||||
arcR = 3;
|
||||
}
|
||||
|
||||
// shape
|
||||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, arcR, arcR);
|
||||
g.fill(rect);
|
||||
g.setPaint(TASK_BORDER_COLOR);
|
||||
|
||||
if (thickBorder) {
|
||||
Stroke originalStroke = g.getStroke();
|
||||
g.setStroke(THICK_TASK_BORDER_STROKE);
|
||||
g.draw(rect);
|
||||
g.setStroke(originalStroke);
|
||||
} else {
|
||||
g.draw(rect);
|
||||
}
|
||||
|
||||
g.setPaint(originalPaint);
|
||||
// text
|
||||
if (scaleFactor == 1.0 && name != null && name.length() > 0) {
|
||||
int boxWidth = width - (2 * TEXT_PADDING);
|
||||
int boxHeight = height - 16 - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2;
|
||||
int boxX = x + width / 2 - boxWidth / 2;
|
||||
int boxY = y + height / 2 - boxHeight / 2 + ICON_PADDING + ICON_PADDING - 2 - 2;
|
||||
|
||||
drawMultilineCentredText(name, boxX, boxY, boxWidth, boxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
protected static Color EVENT_COLOR = new Color(255, 255, 255);
|
||||
|
||||
/**
|
||||
* 重写开始事件
|
||||
* @param graphicInfo
|
||||
* @param image
|
||||
* @param scaleFactor
|
||||
*/
|
||||
@Override
|
||||
public void drawStartEvent(GraphicInfo graphicInfo, BufferedImage image, double scaleFactor) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
g.setPaint(EVENT_COLOR);
|
||||
Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(),
|
||||
graphicInfo.getWidth(), graphicInfo.getHeight());
|
||||
g.fill(circle);
|
||||
g.setPaint(EVENT_BORDER_COLOR);
|
||||
g.draw(circle);
|
||||
g.setPaint(originalPaint);
|
||||
if (image != null) {
|
||||
// calculate coordinates to center image
|
||||
int imageX = (int) Math.round(graphicInfo.getX() + (graphicInfo.getWidth() / 2) - (image.getWidth() / (2 * scaleFactor)));
|
||||
int imageY = (int) Math.round(graphicInfo.getY() + (graphicInfo.getHeight() / 2) - (image.getHeight() / (2 * scaleFactor)));
|
||||
g.drawImage(image, imageX, imageY,
|
||||
(int) (image.getWidth() / scaleFactor), (int) (image.getHeight() / scaleFactor), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写结束事件
|
||||
* @param graphicInfo
|
||||
* @param scaleFactor
|
||||
*/
|
||||
@Override
|
||||
public void drawNoneEndEvent(GraphicInfo graphicInfo, double scaleFactor) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
g.setPaint(EVENT_COLOR);
|
||||
Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(),
|
||||
graphicInfo.getWidth(), graphicInfo.getHeight());
|
||||
g.fill(circle);
|
||||
g.setPaint(EVENT_BORDER_COLOR);
|
||||
// g.setPaint(HIGHLIGHT_COLOR);
|
||||
if (scaleFactor == 1.0) {
|
||||
g.setStroke(END_EVENT_STROKE);
|
||||
} else {
|
||||
g.setStroke(new BasicStroke(2.0f));
|
||||
}
|
||||
g.draw(circle);
|
||||
g.setStroke(originalStroke);
|
||||
g.setPaint(originalPaint);
|
||||
}
|
||||
}
|
||||
@@ -1,404 +0,0 @@
|
||||
package com.klp.flowable.flow;
|
||||
|
||||
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
|
||||
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author XuanXuan
|
||||
* @date 2021/4/5 0:31
|
||||
*/
|
||||
public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator {
|
||||
@Override
|
||||
protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
|
||||
this.prepareBpmnModel(bpmnModel);
|
||||
DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
|
||||
Iterator var13 = bpmnModel.getPools().iterator();
|
||||
|
||||
while (var13.hasNext()) {
|
||||
Pool process = (Pool) var13.next();
|
||||
GraphicInfo subProcesses = bpmnModel.getGraphicInfo(process.getId());
|
||||
processDiagramCanvas.drawPoolOrLane(process.getName(), subProcesses, scaleFactor);
|
||||
}
|
||||
|
||||
var13 = bpmnModel.getProcesses().iterator();
|
||||
|
||||
Process process1;
|
||||
Iterator subProcesses1;
|
||||
while (var13.hasNext()) {
|
||||
process1 = (Process) var13.next();
|
||||
subProcesses1 = process1.getLanes().iterator();
|
||||
|
||||
while (subProcesses1.hasNext()) {
|
||||
Lane artifact = (Lane) subProcesses1.next();
|
||||
GraphicInfo subProcess = bpmnModel.getGraphicInfo(artifact.getId());
|
||||
processDiagramCanvas.drawPoolOrLane(artifact.getName(), subProcess, scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
var13 = bpmnModel.getProcesses().iterator();
|
||||
|
||||
while (var13.hasNext()) {
|
||||
process1 = (Process) var13.next();
|
||||
subProcesses1 = process1.findFlowElementsOfType(FlowNode.class).iterator();
|
||||
|
||||
while (subProcesses1.hasNext()) {
|
||||
FlowNode artifact1 = (FlowNode) subProcesses1.next();
|
||||
if (!this.isPartOfCollapsedSubProcess(artifact1, bpmnModel)) {
|
||||
this.drawActivity(processDiagramCanvas, bpmnModel, artifact1, highLightedActivities, highLightedFlows, scaleFactor, Boolean.valueOf(drawSequenceFlowNameWithNoLabelDI));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var13 = bpmnModel.getProcesses().iterator();
|
||||
|
||||
label75:
|
||||
while (true) {
|
||||
List subProcesses2;
|
||||
do {
|
||||
if (!var13.hasNext()) {
|
||||
return processDiagramCanvas;
|
||||
}
|
||||
|
||||
process1 = (Process) var13.next();
|
||||
subProcesses1 = process1.getArtifacts().iterator();
|
||||
|
||||
while (subProcesses1.hasNext()) {
|
||||
Artifact artifact2 = (Artifact) subProcesses1.next();
|
||||
this.drawArtifact(processDiagramCanvas, bpmnModel, artifact2);
|
||||
}
|
||||
|
||||
subProcesses2 = process1.findFlowElementsOfType(SubProcess.class, true);
|
||||
} while (subProcesses2 == null);
|
||||
|
||||
Iterator artifact3 = subProcesses2.iterator();
|
||||
|
||||
while (true) {
|
||||
GraphicInfo graphicInfo;
|
||||
SubProcess subProcess1;
|
||||
do {
|
||||
do {
|
||||
if (!artifact3.hasNext()) {
|
||||
continue label75;
|
||||
}
|
||||
|
||||
subProcess1 = (SubProcess) artifact3.next();
|
||||
graphicInfo = bpmnModel.getGraphicInfo(subProcess1.getId());
|
||||
} while (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded().booleanValue());
|
||||
} while (this.isPartOfCollapsedSubProcess(subProcess1, bpmnModel));
|
||||
|
||||
Iterator var19 = subProcess1.getArtifacts().iterator();
|
||||
|
||||
while (var19.hasNext()) {
|
||||
Artifact subProcessArtifact = (Artifact) var19.next();
|
||||
this.drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
|
||||
double minX = 1.7976931348623157E308D;
|
||||
double maxX = 0.0D;
|
||||
double minY = 1.7976931348623157E308D;
|
||||
double maxY = 0.0D;
|
||||
|
||||
GraphicInfo nrOfLanes;
|
||||
for (Iterator flowNodes = bpmnModel.getPools().iterator(); flowNodes.hasNext(); maxY = nrOfLanes.getY() + nrOfLanes.getHeight()) {
|
||||
Pool artifacts = (Pool) flowNodes.next();
|
||||
nrOfLanes = bpmnModel.getGraphicInfo(artifacts.getId());
|
||||
minX = nrOfLanes.getX();
|
||||
maxX = nrOfLanes.getX() + nrOfLanes.getWidth();
|
||||
minY = nrOfLanes.getY();
|
||||
}
|
||||
|
||||
List var23 = gatherAllFlowNodes(bpmnModel);
|
||||
Iterator var24 = var23.iterator();
|
||||
|
||||
label155:
|
||||
while (var24.hasNext()) {
|
||||
FlowNode var26 = (FlowNode) var24.next();
|
||||
GraphicInfo artifact = bpmnModel.getGraphicInfo(var26.getId());
|
||||
if (artifact.getX() + artifact.getWidth() > maxX) {
|
||||
maxX = artifact.getX() + artifact.getWidth();
|
||||
}
|
||||
|
||||
if (artifact.getX() < minX) {
|
||||
minX = artifact.getX();
|
||||
}
|
||||
|
||||
if (artifact.getY() + artifact.getHeight() > maxY) {
|
||||
maxY = artifact.getY() + artifact.getHeight();
|
||||
}
|
||||
|
||||
if (artifact.getY() < minY) {
|
||||
minY = artifact.getY();
|
||||
}
|
||||
|
||||
Iterator process = var26.getOutgoingFlows().iterator();
|
||||
|
||||
while (true) {
|
||||
List l;
|
||||
do {
|
||||
if (!process.hasNext()) {
|
||||
continue label155;
|
||||
}
|
||||
|
||||
SequenceFlow graphicInfoList = (SequenceFlow) process.next();
|
||||
l = bpmnModel.getFlowLocationGraphicInfo(graphicInfoList.getId());
|
||||
} while (l == null);
|
||||
|
||||
Iterator graphicInfo = l.iterator();
|
||||
|
||||
while (graphicInfo.hasNext()) {
|
||||
GraphicInfo graphicInfo1 = (GraphicInfo) graphicInfo.next();
|
||||
if (graphicInfo1.getX() > maxX) {
|
||||
maxX = graphicInfo1.getX();
|
||||
}
|
||||
|
||||
if (graphicInfo1.getX() < minX) {
|
||||
minX = graphicInfo1.getX();
|
||||
}
|
||||
|
||||
if (graphicInfo1.getY() > maxY) {
|
||||
maxY = graphicInfo1.getY();
|
||||
}
|
||||
|
||||
if (graphicInfo1.getY() < minY) {
|
||||
minY = graphicInfo1.getY();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List var25 = gatherAllArtifacts(bpmnModel);
|
||||
Iterator var27 = var25.iterator();
|
||||
|
||||
GraphicInfo var37;
|
||||
while (var27.hasNext()) {
|
||||
Artifact var29 = (Artifact) var27.next();
|
||||
GraphicInfo var31 = bpmnModel.getGraphicInfo(var29.getId());
|
||||
if (var31 != null) {
|
||||
if (var31.getX() + var31.getWidth() > maxX) {
|
||||
maxX = var31.getX() + var31.getWidth();
|
||||
}
|
||||
|
||||
if (var31.getX() < minX) {
|
||||
minX = var31.getX();
|
||||
}
|
||||
|
||||
if (var31.getY() + var31.getHeight() > maxY) {
|
||||
maxY = var31.getY() + var31.getHeight();
|
||||
}
|
||||
|
||||
if (var31.getY() < minY) {
|
||||
minY = var31.getY();
|
||||
}
|
||||
}
|
||||
|
||||
List var33 = bpmnModel.getFlowLocationGraphicInfo(var29.getId());
|
||||
if (var33 != null) {
|
||||
Iterator var35 = var33.iterator();
|
||||
|
||||
while (var35.hasNext()) {
|
||||
var37 = (GraphicInfo) var35.next();
|
||||
if (var37.getX() > maxX) {
|
||||
maxX = var37.getX();
|
||||
}
|
||||
|
||||
if (var37.getX() < minX) {
|
||||
minX = var37.getX();
|
||||
}
|
||||
|
||||
if (var37.getY() > maxY) {
|
||||
maxY = var37.getY();
|
||||
}
|
||||
|
||||
if (var37.getY() < minY) {
|
||||
minY = var37.getY();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int var28 = 0;
|
||||
Iterator var30 = bpmnModel.getProcesses().iterator();
|
||||
|
||||
while (var30.hasNext()) {
|
||||
Process var32 = (Process) var30.next();
|
||||
Iterator var34 = var32.getLanes().iterator();
|
||||
|
||||
while (var34.hasNext()) {
|
||||
Lane var36 = (Lane) var34.next();
|
||||
++var28;
|
||||
var37 = bpmnModel.getGraphicInfo(var36.getId());
|
||||
if (var37.getX() + var37.getWidth() > maxX) {
|
||||
maxX = var37.getX() + var37.getWidth();
|
||||
}
|
||||
|
||||
if (var37.getX() < minX) {
|
||||
minX = var37.getX();
|
||||
}
|
||||
|
||||
if (var37.getY() + var37.getHeight() > maxY) {
|
||||
maxY = var37.getY() + var37.getHeight();
|
||||
}
|
||||
|
||||
if (var37.getY() < minY) {
|
||||
minY = var37.getY();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (var23.isEmpty() && bpmnModel.getPools().isEmpty() && var28 == 0) {
|
||||
minX = 0.0D;
|
||||
minY = 0.0D;
|
||||
}
|
||||
|
||||
return new CustomProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
|
||||
}
|
||||
|
||||
|
||||
private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
|
||||
processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
|
||||
|
||||
}
|
||||
|
||||
private static void drawHighLightNow(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
|
||||
processDiagramCanvas.drawHighLightNow((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
|
||||
|
||||
}
|
||||
|
||||
private static void drawHighLightEnd(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
|
||||
processDiagramCanvas.drawHighLightEnd((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
|
||||
FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) {
|
||||
|
||||
ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
|
||||
if (drawInstruction != null) {
|
||||
|
||||
drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);
|
||||
|
||||
// Gather info on the multi instance marker
|
||||
boolean multiInstanceSequential = false;
|
||||
boolean multiInstanceParallel = false;
|
||||
boolean collapsed = false;
|
||||
if (flowNode instanceof Activity) {
|
||||
Activity activity = (Activity) flowNode;
|
||||
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
|
||||
if (multiInstanceLoopCharacteristics != null) {
|
||||
multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
|
||||
multiInstanceParallel = !multiInstanceSequential;
|
||||
}
|
||||
}
|
||||
|
||||
// Gather info on the collapsed marker
|
||||
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
|
||||
if (flowNode instanceof SubProcess) {
|
||||
collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
|
||||
} else if (flowNode instanceof CallActivity) {
|
||||
collapsed = true;
|
||||
}
|
||||
|
||||
if (scaleFactor == 1.0) {
|
||||
// Actually draw the markers
|
||||
processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
|
||||
multiInstanceSequential, multiInstanceParallel, collapsed);
|
||||
}
|
||||
|
||||
// Draw highlighted activities
|
||||
if (highLightedActivities.contains(flowNode.getId())) {
|
||||
|
||||
if (highLightedActivities.get(highLightedActivities.size() - 1).equals(flowNode.getId())
|
||||
&& !"endenv".equals(flowNode.getId())) {
|
||||
if ((flowNode.getId().contains("Event_"))) {
|
||||
drawHighLightEnd((CustomProcessDiagramCanvas) processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
|
||||
} else {
|
||||
drawHighLightNow((CustomProcessDiagramCanvas) processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
|
||||
}
|
||||
} else {
|
||||
drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Outgoing transitions of activity
|
||||
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
|
||||
boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
|
||||
String defaultFlow = null;
|
||||
if (flowNode instanceof Activity) {
|
||||
defaultFlow = ((Activity) flowNode).getDefaultFlow();
|
||||
} else if (flowNode instanceof Gateway) {
|
||||
defaultFlow = ((Gateway) flowNode).getDefaultFlow();
|
||||
}
|
||||
|
||||
boolean isDefault = false;
|
||||
if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) {
|
||||
isDefault = true;
|
||||
}
|
||||
boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway);
|
||||
|
||||
String sourceRef = sequenceFlow.getSourceRef();
|
||||
String targetRef = sequenceFlow.getTargetRef();
|
||||
FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
|
||||
FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
|
||||
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
|
||||
if (graphicInfoList != null && graphicInfoList.size() > 0) {
|
||||
graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
|
||||
int xPoints[] = new int[graphicInfoList.size()];
|
||||
int yPoints[] = new int[graphicInfoList.size()];
|
||||
|
||||
for (int i = 1; i < graphicInfoList.size(); i++) {
|
||||
GraphicInfo graphicInfo = graphicInfoList.get(i);
|
||||
GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
|
||||
|
||||
if (i == 1) {
|
||||
xPoints[0] = (int) previousGraphicInfo.getX();
|
||||
yPoints[0] = (int) previousGraphicInfo.getY();
|
||||
}
|
||||
xPoints[i] = (int) graphicInfo.getX();
|
||||
yPoints[i] = (int) graphicInfo.getY();
|
||||
|
||||
}
|
||||
|
||||
processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor);
|
||||
|
||||
|
||||
// Draw sequenceflow label
|
||||
GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
|
||||
if (labelGraphicInfo != null) {
|
||||
processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
|
||||
} else {
|
||||
if (drawSequenceFlowNameWithNoLabelDI) {
|
||||
GraphicInfo lineCenter = getLineCenter(graphicInfoList);
|
||||
processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nested elements
|
||||
if (flowNode instanceof FlowElementsContainer) {
|
||||
for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
|
||||
if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) {
|
||||
drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
|
||||
highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
package com.klp.flowable.flow;
|
||||
|
||||
import com.googlecode.aviator.AviatorEvaluator;
|
||||
import com.googlecode.aviator.Expression;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Xuan xuan
|
||||
* @date 2021/4/19 20:51
|
||||
*/
|
||||
public class FindNextNodeUtil {
|
||||
|
||||
/**
|
||||
* 获取下一步骤的用户任务
|
||||
*
|
||||
* @param repositoryService
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
public static List<UserTask> getNextUserTasks(RepositoryService repositoryService, org.flowable.task.api.Task task, Map<String, Object> map) {
|
||||
List<UserTask> data = new ArrayList<>();
|
||||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
|
||||
Process mainProcess = bpmnModel.getMainProcess();
|
||||
Collection<FlowElement> flowElements = mainProcess.getFlowElements();
|
||||
String key = task.getTaskDefinitionKey();
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(key);
|
||||
next(flowElements, flowElement, map, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void next(Collection<FlowElement> flowElements, FlowElement flowElement, Map<String, Object> map, List<UserTask> nextUser) {
|
||||
//如果是结束节点
|
||||
if (flowElement instanceof EndEvent) {
|
||||
//如果是子任务的结束节点
|
||||
if (getSubProcess(flowElements, flowElement) != null) {
|
||||
flowElement = getSubProcess(flowElements, flowElement);
|
||||
}
|
||||
}
|
||||
//获取Task的出线信息--可以拥有多个
|
||||
List<SequenceFlow> outGoingFlows = null;
|
||||
if (flowElement instanceof Task) {
|
||||
outGoingFlows = ((Task) flowElement).getOutgoingFlows();
|
||||
} else if (flowElement instanceof Gateway) {
|
||||
outGoingFlows = ((Gateway) flowElement).getOutgoingFlows();
|
||||
} else if (flowElement instanceof StartEvent) {
|
||||
outGoingFlows = ((StartEvent) flowElement).getOutgoingFlows();
|
||||
} else if (flowElement instanceof SubProcess) {
|
||||
outGoingFlows = ((SubProcess) flowElement).getOutgoingFlows();
|
||||
} else if (flowElement instanceof CallActivity) {
|
||||
outGoingFlows = ((CallActivity) flowElement).getOutgoingFlows();
|
||||
}
|
||||
if (outGoingFlows != null && outGoingFlows.size() > 0) {
|
||||
//遍历所有的出线--找到可以正确执行的那一条
|
||||
for (SequenceFlow sequenceFlow : outGoingFlows) {
|
||||
//1.有表达式,且为true
|
||||
//2.无表达式
|
||||
String expression = sequenceFlow.getConditionExpression();
|
||||
if (expression == null || expressionResult(map, expression.substring(expression.lastIndexOf("{") + 1, expression.lastIndexOf("}")))) {
|
||||
//出线的下一节点
|
||||
String nextFlowElementID = sequenceFlow.getTargetRef();
|
||||
if (checkSubProcess(nextFlowElementID, flowElements, nextUser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//查询下一节点的信息
|
||||
FlowElement nextFlowElement = getFlowElementById(nextFlowElementID, flowElements);
|
||||
//调用流程
|
||||
if (nextFlowElement instanceof CallActivity) {
|
||||
CallActivity ca = (CallActivity) nextFlowElement;
|
||||
if (ca.getLoopCharacteristics() != null) {
|
||||
UserTask userTask = new UserTask();
|
||||
userTask.setId(ca.getId());
|
||||
|
||||
userTask.setId(ca.getId());
|
||||
userTask.setLoopCharacteristics(ca.getLoopCharacteristics());
|
||||
userTask.setName(ca.getName());
|
||||
nextUser.add(userTask);
|
||||
}
|
||||
next(flowElements, nextFlowElement, map, nextUser);
|
||||
}
|
||||
//用户任务
|
||||
if (nextFlowElement instanceof UserTask) {
|
||||
nextUser.add((UserTask) nextFlowElement);
|
||||
}
|
||||
//排他网关
|
||||
else if (nextFlowElement instanceof ExclusiveGateway) {
|
||||
next(flowElements, nextFlowElement, map, nextUser);
|
||||
}
|
||||
//并行网关
|
||||
else if (nextFlowElement instanceof ParallelGateway) {
|
||||
next(flowElements, nextFlowElement, map, nextUser);
|
||||
}
|
||||
//接收任务
|
||||
else if (nextFlowElement instanceof ReceiveTask) {
|
||||
next(flowElements, nextFlowElement, map, nextUser);
|
||||
}
|
||||
//服务任务
|
||||
else if (nextFlowElement instanceof ServiceTask) {
|
||||
next(flowElements, nextFlowElement, map, nextUser);
|
||||
}
|
||||
//子任务的起点
|
||||
else if (nextFlowElement instanceof StartEvent) {
|
||||
next(flowElements, nextFlowElement, map, nextUser);
|
||||
}
|
||||
//结束节点
|
||||
else if (nextFlowElement instanceof EndEvent) {
|
||||
next(flowElements, nextFlowElement, map, nextUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是多实例子流程并且需要设置集合类型变量
|
||||
*/
|
||||
public static boolean checkSubProcess(String Id, Collection<FlowElement> flowElements, List<UserTask> nextUser) {
|
||||
for (FlowElement flowElement1 : flowElements) {
|
||||
if (flowElement1 instanceof SubProcess && flowElement1.getId().equals(Id)) {
|
||||
|
||||
SubProcess sp = (SubProcess) flowElement1;
|
||||
if (sp.getLoopCharacteristics() != null) {
|
||||
String inputDataItem = sp.getLoopCharacteristics().getInputDataItem();
|
||||
UserTask userTask = new UserTask();
|
||||
userTask.setId(sp.getId());
|
||||
userTask.setLoopCharacteristics(sp.getLoopCharacteristics());
|
||||
userTask.setName(sp.getName());
|
||||
nextUser.add(userTask);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询一个节点的是否子任务中的节点,如果是,返回子任务
|
||||
*
|
||||
* @param flowElements 全流程的节点集合
|
||||
* @param flowElement 当前节点
|
||||
* @return
|
||||
*/
|
||||
public static FlowElement getSubProcess(Collection<FlowElement> flowElements, FlowElement flowElement) {
|
||||
for (FlowElement flowElement1 : flowElements) {
|
||||
if (flowElement1 instanceof SubProcess) {
|
||||
for (FlowElement flowElement2 : ((SubProcess) flowElement1).getFlowElements()) {
|
||||
if (flowElement.equals(flowElement2)) {
|
||||
return flowElement1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据ID查询流程节点对象, 如果是子任务,则返回子任务的开始节点
|
||||
*
|
||||
* @param Id 节点ID
|
||||
* @param flowElements 流程节点集合
|
||||
* @return
|
||||
*/
|
||||
public static FlowElement getFlowElementById(String Id, Collection<FlowElement> flowElements) {
|
||||
for (FlowElement flowElement : flowElements) {
|
||||
if (flowElement.getId().equals(Id)) {
|
||||
//如果是子任务,则查询出子任务的开始节点
|
||||
if (flowElement instanceof SubProcess) {
|
||||
return getStartFlowElement(((SubProcess) flowElement).getFlowElements());
|
||||
}
|
||||
return flowElement;
|
||||
}
|
||||
if (flowElement instanceof SubProcess) {
|
||||
FlowElement flowElement1 = getFlowElementById(Id, ((SubProcess) flowElement).getFlowElements());
|
||||
if (flowElement1 != null) {
|
||||
return flowElement1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回流程的开始节点
|
||||
*
|
||||
* @param flowElements 节点集合
|
||||
* @description:
|
||||
*/
|
||||
public static FlowElement getStartFlowElement(Collection<FlowElement> flowElements) {
|
||||
for (FlowElement flowElement : flowElements) {
|
||||
if (flowElement instanceof StartEvent) {
|
||||
return flowElement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验el表达式
|
||||
*
|
||||
* @param map
|
||||
* @param expression
|
||||
* @return
|
||||
*/
|
||||
public static boolean expressionResult(Map<String, Object> map, String expression) {
|
||||
Expression exp = AviatorEvaluator.compile(expression);
|
||||
final Object execute = exp.execute(map);
|
||||
return Boolean.parseBoolean(String.valueOf(execute));
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.klp.flowable.flow;
|
||||
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.flowable.spring.boot.EngineConfigurationConfigurer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
/**
|
||||
* @author XuanXuan
|
||||
* @date 2021/4/5 01:32
|
||||
*/
|
||||
@Configuration
|
||||
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
|
||||
|
||||
@Override
|
||||
public void configure(SpringProcessEngineConfiguration engineConfiguration) {
|
||||
engineConfiguration.setActivityFontName("宋体");
|
||||
engineConfiguration.setLabelFontName("宋体");
|
||||
engineConfiguration.setAnnotationFontName("宋体");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,704 +0,0 @@
|
||||
package com.klp.flowable.flow;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
|
||||
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author XuanXuan
|
||||
* @date 2021-04-03 23:57
|
||||
*/
|
||||
@Slf4j
|
||||
public class FlowableUtils {
|
||||
|
||||
/**
|
||||
* 根据节点,获取入口连线
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
|
||||
List<SequenceFlow> sequenceFlows = null;
|
||||
if (source instanceof FlowNode) {
|
||||
sequenceFlows = ((FlowNode) source).getIncomingFlows();
|
||||
} else if (source instanceof Gateway) {
|
||||
sequenceFlows = ((Gateway) source).getIncomingFlows();
|
||||
} else if (source instanceof SubProcess) {
|
||||
sequenceFlows = ((SubProcess) source).getIncomingFlows();
|
||||
} else if (source instanceof StartEvent) {
|
||||
sequenceFlows = ((StartEvent) source).getIncomingFlows();
|
||||
} else if (source instanceof EndEvent) {
|
||||
sequenceFlows = ((EndEvent) source).getIncomingFlows();
|
||||
}
|
||||
return sequenceFlows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据节点,获取出口连线
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
|
||||
List<SequenceFlow> sequenceFlows = null;
|
||||
if (source instanceof FlowNode) {
|
||||
sequenceFlows = ((FlowNode) source).getOutgoingFlows();
|
||||
} else if (source instanceof Gateway) {
|
||||
sequenceFlows = ((Gateway) source).getOutgoingFlows();
|
||||
} else if (source instanceof SubProcess) {
|
||||
sequenceFlows = ((SubProcess) source).getOutgoingFlows();
|
||||
} else if (source instanceof StartEvent) {
|
||||
sequenceFlows = ((StartEvent) source).getOutgoingFlows();
|
||||
} else if (source instanceof EndEvent) {
|
||||
sequenceFlows = ((EndEvent) source).getOutgoingFlows();
|
||||
}
|
||||
return sequenceFlows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部节点列表,包含子流程节点
|
||||
* @param flowElements
|
||||
* @param allElements
|
||||
* @return
|
||||
*/
|
||||
public static Collection<FlowElement> getAllElements(Collection<FlowElement> flowElements, Collection<FlowElement> allElements) {
|
||||
allElements = allElements == null ? new ArrayList<>() : allElements;
|
||||
|
||||
for (FlowElement flowElement : flowElements) {
|
||||
allElements.add(flowElement);
|
||||
if (flowElement instanceof SubProcess) {
|
||||
// 继续深入子流程,进一步获取子流程
|
||||
allElements = FlowableUtils.getAllElements(((SubProcess) flowElement).getFlowElements(), allElements);
|
||||
}
|
||||
}
|
||||
return allElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代获取父级任务节点列表,向前找
|
||||
* @param source 起始节点
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param userTaskList 已找到的用户任务节点
|
||||
* @return
|
||||
*/
|
||||
public static List<UserTask> iteratorFindParentUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
|
||||
userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
|
||||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
||||
if (source instanceof StartEvent && source.getSubProcess() != null) {
|
||||
userTaskList = iteratorFindParentUserTasks(source.getSubProcess(), hasSequenceFlow, userTaskList);
|
||||
}
|
||||
|
||||
// 根据类型,获取入口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 类型为用户节点,则新增父级节点
|
||||
if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
|
||||
userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement());
|
||||
continue;
|
||||
}
|
||||
// 类型为子流程,则添加子流程开始节点出口处相连的节点
|
||||
if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
|
||||
// 获取子流程用户任务节点
|
||||
List<UserTask> childUserTaskList = findChildProcessUserTasks((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null);
|
||||
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
|
||||
if (childUserTaskList != null && childUserTaskList.size() > 0) {
|
||||
userTaskList.addAll(childUserTaskList);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 继续迭代
|
||||
userTaskList = iteratorFindParentUserTasks(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList);
|
||||
}
|
||||
}
|
||||
return userTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找
|
||||
* @param source 起始节点
|
||||
* @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param userTaskList 需要撤回的用户任务列表
|
||||
* @return
|
||||
*/
|
||||
public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
|
||||
|
||||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
||||
if (source instanceof StartEvent && source.getSubProcess() != null) {
|
||||
userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList);
|
||||
}
|
||||
|
||||
// 根据类型,获取出口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
|
||||
if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) {
|
||||
userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
|
||||
continue;
|
||||
}
|
||||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
||||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
|
||||
List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null);
|
||||
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
|
||||
if (childUserTaskList != null && childUserTaskList.size() > 0) {
|
||||
userTaskList.addAll(childUserTaskList);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 继续迭代
|
||||
userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList);
|
||||
}
|
||||
}
|
||||
return userTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代获取子流程用户任务节点
|
||||
* @param source 起始节点
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param userTaskList 需要撤回的用户任务列表
|
||||
* @return
|
||||
*/
|
||||
public static List<UserTask> findChildProcessUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
|
||||
|
||||
// 根据类型,获取出口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
|
||||
if (sequenceFlow.getTargetFlowElement() instanceof UserTask) {
|
||||
userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
|
||||
continue;
|
||||
}
|
||||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
||||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
|
||||
List<UserTask> childUserTaskList = findChildProcessUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null);
|
||||
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
|
||||
if (childUserTaskList != null && childUserTaskList.size() > 0) {
|
||||
userTaskList.addAll(childUserTaskList);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 继续迭代
|
||||
userTaskList = findChildProcessUserTasks(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList);
|
||||
}
|
||||
}
|
||||
return userTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从后向前寻路,获取所有脏线路上的点
|
||||
* @param source 起始节点
|
||||
* @param passRoads 已经经过的点集合
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param targets 目标脏线路终点
|
||||
* @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储
|
||||
* @return
|
||||
*/
|
||||
public static Set<String> iteratorFindDirtyRoads(FlowElement source, List<String> passRoads, Set<String> hasSequenceFlow, List<String> targets, Set<String> dirtyRoads) {
|
||||
passRoads = passRoads == null ? new ArrayList<>() : passRoads;
|
||||
dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads;
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
|
||||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
||||
if (source instanceof StartEvent && source.getSubProcess() != null) {
|
||||
dirtyRoads = iteratorFindDirtyRoads(source.getSubProcess(), passRoads, hasSequenceFlow, targets, dirtyRoads);
|
||||
}
|
||||
|
||||
// 根据类型,获取入口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 新增经过的路线
|
||||
passRoads.add(sequenceFlow.getSourceFlowElement().getId());
|
||||
// 如果此点为目标点,确定经过的路线为脏线路,添加点到脏线路中,然后找下个连线
|
||||
if (targets.contains(sequenceFlow.getSourceFlowElement().getId())) {
|
||||
dirtyRoads.addAll(passRoads);
|
||||
continue;
|
||||
}
|
||||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
||||
if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
|
||||
dirtyRoads = findChildProcessAllDirtyRoad((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, dirtyRoads);
|
||||
// 是否存在子流程上,true 是,false 否
|
||||
Boolean isInChildProcess = dirtyTargetInChildProcess((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, targets, null);
|
||||
if (isInChildProcess) {
|
||||
// 已在子流程上找到,该路线结束
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 继续迭代
|
||||
dirtyRoads = iteratorFindDirtyRoads(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, targets, dirtyRoads);
|
||||
}
|
||||
}
|
||||
return dirtyRoads;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代获取子流程脏路线
|
||||
* 说明,假如回退的点就是子流程,那么也肯定会回退到子流程最初的用户任务节点,因此子流程中的节点全是脏路线
|
||||
* @param source 起始节点
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储
|
||||
* @return
|
||||
*/
|
||||
public static Set<String> findChildProcessAllDirtyRoad(FlowElement source, Set<String> hasSequenceFlow, Set<String> dirtyRoads) {
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads;
|
||||
|
||||
// 根据类型,获取出口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 添加脏路线
|
||||
dirtyRoads.add(sequenceFlow.getTargetFlowElement().getId());
|
||||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
||||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
|
||||
dirtyRoads = findChildProcessAllDirtyRoad((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, dirtyRoads);
|
||||
}
|
||||
// 继续迭代
|
||||
dirtyRoads = findChildProcessAllDirtyRoad(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, dirtyRoads);
|
||||
}
|
||||
}
|
||||
return dirtyRoads;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断脏路线结束节点是否在子流程上
|
||||
* @param source 起始节点
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param targets 判断脏路线节点是否存在子流程上,只要存在一个,说明脏路线只到子流程为止
|
||||
* @param inChildProcess 是否存在子流程上,true 是,false 否
|
||||
* @return
|
||||
*/
|
||||
public static Boolean dirtyTargetInChildProcess(FlowElement source, Set<String> hasSequenceFlow, List<String> targets, Boolean inChildProcess) {
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
inChildProcess = inChildProcess == null ? false : inChildProcess;
|
||||
|
||||
// 根据类型,获取出口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||
|
||||
if (sequenceFlows != null && !inChildProcess) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 如果发现目标点在子流程上存在,说明只到子流程为止
|
||||
if (targets.contains(sequenceFlow.getTargetFlowElement().getId())) {
|
||||
inChildProcess = true;
|
||||
break;
|
||||
}
|
||||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
||||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
|
||||
inChildProcess = dirtyTargetInChildProcess((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, targets, inChildProcess);
|
||||
}
|
||||
// 继续迭代
|
||||
inChildProcess = dirtyTargetInChildProcess(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, targets, inChildProcess);
|
||||
}
|
||||
}
|
||||
return inChildProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
|
||||
* 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
|
||||
* @param source 起始节点
|
||||
* @param isSequential 是否串行
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param targetKsy 目标节点
|
||||
* @return
|
||||
*/
|
||||
public static Boolean iteratorCheckSequentialReferTarget(FlowElement source, String targetKsy, Set<String> hasSequenceFlow, Boolean isSequential) {
|
||||
isSequential = isSequential == null ? true : isSequential;
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
|
||||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
||||
if (source instanceof StartEvent && source.getSubProcess() != null) {
|
||||
isSequential = iteratorCheckSequentialReferTarget(source.getSubProcess(), targetKsy, hasSequenceFlow, isSequential);
|
||||
}
|
||||
|
||||
// 根据类型,获取入口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 如果目标节点已被判断为并行,后面都不需要执行,直接返回
|
||||
if (isSequential == false) {
|
||||
break;
|
||||
}
|
||||
// 这条线路存在目标节点,这条线路完成,进入下个线路
|
||||
if (targetKsy.equals(sequenceFlow.getSourceFlowElement().getId())) {
|
||||
continue;
|
||||
}
|
||||
if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) {
|
||||
isSequential = false;
|
||||
break;
|
||||
}
|
||||
// 否则就继续迭代
|
||||
isSequential = iteratorCheckSequentialReferTarget(sequenceFlow.getSourceFlowElement(), targetKsy, hasSequenceFlow, isSequential);
|
||||
}
|
||||
}
|
||||
return isSequential;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从后向前寻路,获取到达节点的所有路线
|
||||
* 不存在直接回退到子流程,但是存在回退到父级流程的情况
|
||||
* @param source 起始节点
|
||||
* @param passRoads 已经经过的点集合
|
||||
* @param roads 路线
|
||||
* @return
|
||||
*/
|
||||
public static List<List<UserTask>> findRoad(FlowElement source, List<UserTask> passRoads, Set<String> hasSequenceFlow, List<List<UserTask>> roads) {
|
||||
passRoads = passRoads == null ? new ArrayList<>() : passRoads;
|
||||
roads = roads == null ? new ArrayList<>() : roads;
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
|
||||
|
||||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
||||
if (source instanceof StartEvent && source.getSubProcess() != null) {
|
||||
roads = findRoad(source.getSubProcess(), passRoads, hasSequenceFlow, roads);
|
||||
}
|
||||
|
||||
// 根据类型,获取入口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||
|
||||
if (sequenceFlows != null && sequenceFlows.size() != 0) {
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
// 添加经过路线
|
||||
if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
|
||||
passRoads.add((UserTask) sequenceFlow.getSourceFlowElement());
|
||||
}
|
||||
// 继续迭代
|
||||
roads = findRoad(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, roads);
|
||||
}
|
||||
} else {
|
||||
// 添加路线
|
||||
roads.add(passRoads);
|
||||
}
|
||||
return roads;
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史节点数据清洗,清洗掉又回滚导致的脏数据
|
||||
* @param allElements 全部节点信息
|
||||
* @param historicTaskInstanceList 历史任务实例信息,数据采用开始时间升序
|
||||
* @return
|
||||
*/
|
||||
public static List<String> historicTaskInstanceClean(Collection<FlowElement> allElements, List<HistoricTaskInstance> historicTaskInstanceList) {
|
||||
// 会签节点收集
|
||||
List<String> multiTask = new ArrayList<>();
|
||||
allElements.forEach(flowElement -> {
|
||||
if (flowElement instanceof UserTask) {
|
||||
// 如果该节点的行为为会签行为,说明该节点为会签节点
|
||||
if (((UserTask) flowElement).getBehavior() instanceof ParallelMultiInstanceBehavior || ((UserTask) flowElement).getBehavior() instanceof SequentialMultiInstanceBehavior) {
|
||||
multiTask.add(flowElement.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
// 循环放入栈,栈 LIFO:后进先出
|
||||
Stack<HistoricTaskInstance> stack = new Stack<>();
|
||||
historicTaskInstanceList.forEach(item -> stack.push(item));
|
||||
// 清洗后的历史任务实例
|
||||
List<String> lastHistoricTaskInstanceList = new ArrayList<>();
|
||||
// 网关存在可能只走了部分分支情况,且还存在跳转废弃数据以及其他分支数据的干扰,因此需要对历史节点数据进行清洗
|
||||
// 临时用户任务 key
|
||||
StringBuilder userTaskKey = null;
|
||||
// 临时被删掉的任务 key,存在并行情况
|
||||
List<String> deleteKeyList = new ArrayList<>();
|
||||
// 临时脏数据线路
|
||||
List<Set<String>> dirtyDataLineList = new ArrayList<>();
|
||||
// 由某个点跳到会签点,此时出现多个会签实例对应 1 个跳转情况,需要把这些连续脏数据都找到
|
||||
// 会签特殊处理下标
|
||||
int multiIndex = -1;
|
||||
// 会签特殊处理 key
|
||||
StringBuilder multiKey = null;
|
||||
// 会签特殊处理操作标识
|
||||
boolean multiOpera = false;
|
||||
while (!stack.empty()) {
|
||||
// 从这里开始 userTaskKey 都还是上个栈的 key
|
||||
// 是否是脏数据线路上的点
|
||||
final boolean[] isDirtyData = {false};
|
||||
for (Set<String> oldDirtyDataLine : dirtyDataLineList) {
|
||||
if (oldDirtyDataLine.contains(stack.peek().getTaskDefinitionKey())) {
|
||||
isDirtyData[0] = true;
|
||||
}
|
||||
}
|
||||
// 删除原因不为空,说明从这条数据开始回跳或者回退的
|
||||
// MI_END:会签完成后,其他未签到节点的删除原因,不在处理范围内
|
||||
if (stack.peek().getDeleteReason() != null && !stack.peek().getDeleteReason().equals("MI_END")) {
|
||||
// 可以理解为脏线路起点
|
||||
String dirtyPoint = "";
|
||||
if (stack.peek().getDeleteReason().indexOf("Change activity to ") >= 0) {
|
||||
dirtyPoint = stack.peek().getDeleteReason().replace("Change activity to ", "");
|
||||
}
|
||||
// 会签回退删除原因有点不同
|
||||
if (stack.peek().getDeleteReason().indexOf("Change parent activity to ") >= 0) {
|
||||
dirtyPoint = stack.peek().getDeleteReason().replace("Change parent activity to ", "");
|
||||
}
|
||||
FlowElement dirtyTask = null;
|
||||
// 获取变更节点的对应的入口处连线
|
||||
// 如果是网关并行回退情况,会变成两条脏数据路线,效果一样
|
||||
for (FlowElement flowElement : allElements) {
|
||||
if (flowElement.getId().equals(stack.peek().getTaskDefinitionKey())) {
|
||||
dirtyTask = flowElement;
|
||||
}
|
||||
}
|
||||
// 获取脏数据线路
|
||||
Set<String> dirtyDataLine = FlowableUtils.iteratorFindDirtyRoads(dirtyTask, null, null, Arrays.asList(dirtyPoint.split(",")), null);
|
||||
// 自己本身也是脏线路上的点,加进去
|
||||
dirtyDataLine.add(stack.peek().getTaskDefinitionKey());
|
||||
log.info(stack.peek().getTaskDefinitionKey() + "点脏路线集合:" + dirtyDataLine);
|
||||
// 是全新的需要添加的脏线路
|
||||
boolean isNewDirtyData = true;
|
||||
for (int i = 0; i < dirtyDataLineList.size(); i++) {
|
||||
// 如果发现他的上个节点在脏线路内,说明这个点可能是并行的节点,或者连续驳回
|
||||
// 这时,都以之前的脏线路节点为标准,只需合并脏线路即可,也就是路线补全
|
||||
if (dirtyDataLineList.get(i).contains(userTaskKey.toString())) {
|
||||
isNewDirtyData = false;
|
||||
dirtyDataLineList.get(i).addAll(dirtyDataLine);
|
||||
}
|
||||
}
|
||||
// 已确定时全新的脏线路
|
||||
if (isNewDirtyData) {
|
||||
// deleteKey 单一路线驳回到并行,这种同时生成多个新实例记录情况,这时 deleteKey 其实是由多个值组成
|
||||
// 按照逻辑,回退后立刻生成的实例记录就是回退的记录
|
||||
// 至于驳回所生成的 Key,直接从删除原因中获取,因为存在驳回到并行的情况
|
||||
deleteKeyList.add(dirtyPoint + ",");
|
||||
dirtyDataLineList.add(dirtyDataLine);
|
||||
}
|
||||
// 添加后,现在这个点变成脏线路上的点了
|
||||
isDirtyData[0] = true;
|
||||
}
|
||||
// 如果不是脏线路上的点,说明是有效数据,添加历史实例 Key
|
||||
if (!isDirtyData[0]) {
|
||||
lastHistoricTaskInstanceList.add(stack.peek().getTaskDefinitionKey());
|
||||
}
|
||||
// 校验脏线路是否结束
|
||||
for (int i = 0; i < deleteKeyList.size(); i ++) {
|
||||
// 如果发现脏数据属于会签,记录下下标与对应 Key,以备后续比对,会签脏数据范畴开始
|
||||
if (multiKey == null && multiTask.contains(stack.peek().getTaskDefinitionKey())
|
||||
&& deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) {
|
||||
multiIndex = i;
|
||||
multiKey = new StringBuilder(stack.peek().getTaskDefinitionKey());
|
||||
}
|
||||
// 会签脏数据处理,节点退回会签清空
|
||||
// 如果在会签脏数据范畴中发现 Key改变,说明会签脏数据在上个节点就结束了,可以把会签脏数据删掉
|
||||
if (multiKey != null && !multiKey.toString().equals(stack.peek().getTaskDefinitionKey())) {
|
||||
deleteKeyList.set(multiIndex , deleteKeyList.get(multiIndex).replace(stack.peek().getTaskDefinitionKey() + ",", ""));
|
||||
multiKey = null;
|
||||
// 结束进行下校验删除
|
||||
multiOpera = true;
|
||||
}
|
||||
// 其他脏数据处理
|
||||
// 发现该路线最后一条脏数据,说明这条脏数据线路处理完了,删除脏数据信息
|
||||
// 脏数据产生的新实例中是否包含这条数据
|
||||
if (multiKey == null && deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) {
|
||||
// 删除匹配到的部分
|
||||
deleteKeyList.set(i , deleteKeyList.get(i).replace(stack.peek().getTaskDefinitionKey() + ",", ""));
|
||||
}
|
||||
// 如果每组中的元素都以匹配过,说明脏数据结束
|
||||
if ("".equals(deleteKeyList.get(i))) {
|
||||
// 同时删除脏数据
|
||||
deleteKeyList.remove(i);
|
||||
dirtyDataLineList.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 会签数据处理需要在循环外处理,否则可能导致溢出
|
||||
// 会签的数据肯定是之前放进去的所以理论上不会溢出,但还是校验下
|
||||
if (multiOpera && deleteKeyList.size() > multiIndex && "".equals(deleteKeyList.get(multiIndex))) {
|
||||
// 同时删除脏数据
|
||||
deleteKeyList.remove(multiIndex);
|
||||
dirtyDataLineList.remove(multiIndex);
|
||||
multiIndex = -1;
|
||||
multiOpera = false;
|
||||
}
|
||||
// pop() 方法与 peek() 方法不同,在返回值的同时,会把值从栈中移除
|
||||
// 保存新的 userTaskKey 在下个循环中使用
|
||||
userTaskKey = new StringBuilder(stack.pop().getTaskDefinitionKey());
|
||||
}
|
||||
log.info("清洗后的历史节点数据:" + lastHistoricTaskInstanceList);
|
||||
return lastHistoricTaskInstanceList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 深搜递归获取流程未通过的节点
|
||||
* @param bpmnModel 流程模型
|
||||
* @param unfinishedTaskSet 未结束的任务节点
|
||||
* @param finishedSequenceFlowSet 已经完成的连线
|
||||
* @param finishedTaskSet 已完成的任务节点
|
||||
* @return
|
||||
*/
|
||||
public static Set<String> dfsFindRejects(BpmnModel bpmnModel, Set<String> unfinishedTaskSet, Set<String> finishedSequenceFlowSet, Set<String> finishedTaskSet) {
|
||||
if (ObjectUtil.isNull(bpmnModel)) {
|
||||
throw new ServiceException("流程模型不存在");
|
||||
}
|
||||
Collection<FlowElement> allElements = getAllElements(bpmnModel.getMainProcess().getFlowElements(), null);
|
||||
Set<String> rejectedSet = new HashSet<>();
|
||||
for (FlowElement flowElement : allElements) {
|
||||
// 用户节点且未结束元素
|
||||
if (flowElement instanceof UserTask && unfinishedTaskSet.contains(flowElement.getId())) {
|
||||
List<String> hasSequenceFlow = iteratorFindFinishes(flowElement, null);
|
||||
List<String> rejects = iteratorFindRejects(flowElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, null);
|
||||
rejectedSet.addAll(rejects);
|
||||
}
|
||||
}
|
||||
return rejectedSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代获取父级节点列表,向前找
|
||||
* @param source 起始节点
|
||||
* @param hasSequenceFlow 已经经过的连线的ID,用于判断线路是否重复
|
||||
* @return
|
||||
*/
|
||||
public static List<String> iteratorFindFinishes(FlowElement source, List<String> hasSequenceFlow) {
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new ArrayList<>() : hasSequenceFlow;
|
||||
|
||||
// 根据类型,获取入口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
FlowElement finishedElement = sequenceFlow.getSourceFlowElement();
|
||||
// 类型为子流程,则添加子流程开始节点出口处相连的节点
|
||||
if (finishedElement instanceof SubProcess) {
|
||||
FlowElement firstElement = (StartEvent) ((SubProcess) finishedElement).getFlowElements().toArray()[0];
|
||||
// 获取子流程的连线
|
||||
hasSequenceFlow.addAll(iteratorFindFinishes(firstElement, null));
|
||||
}
|
||||
// 继续迭代
|
||||
hasSequenceFlow = iteratorFindFinishes(finishedElement, hasSequenceFlow);
|
||||
}
|
||||
}
|
||||
return hasSequenceFlow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找
|
||||
* @param source 起始节点
|
||||
* @param finishedSequenceFlowSet 已经完成的连线
|
||||
* @param finishedTaskSet 已经完成的任务节点
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param rejectedList 未通过的元素
|
||||
* @return
|
||||
*/
|
||||
public static List<String> iteratorFindRejects(FlowElement source, Set<String> finishedSequenceFlowSet, Set<String> finishedTaskSet
|
||||
, List<String> hasSequenceFlow, List<String> rejectedList) {
|
||||
hasSequenceFlow = hasSequenceFlow == null ? new ArrayList<>() : hasSequenceFlow;
|
||||
rejectedList = rejectedList == null ? new ArrayList<>() : rejectedList;
|
||||
|
||||
// 根据类型,获取出口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||
|
||||
if (sequenceFlows != null) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
FlowElement targetElement = sequenceFlow.getTargetFlowElement();
|
||||
// 添加未完成的节点
|
||||
if (finishedTaskSet.contains(targetElement.getId())) {
|
||||
rejectedList.add(targetElement.getId());
|
||||
}
|
||||
// 添加未完成的连线
|
||||
if (finishedSequenceFlowSet.contains(sequenceFlow.getId())) {
|
||||
rejectedList.add(sequenceFlow.getId());
|
||||
}
|
||||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
||||
if (targetElement instanceof SubProcess) {
|
||||
FlowElement firstElement = (FlowElement) (((SubProcess) targetElement).getFlowElements().toArray()[0]);
|
||||
List<String> childList = iteratorFindRejects(firstElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, null);
|
||||
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
|
||||
if (childList != null && childList.size() > 0) {
|
||||
rejectedList.addAll(childList);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 继续迭代
|
||||
rejectedList = iteratorFindRejects(targetElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, rejectedList);
|
||||
}
|
||||
}
|
||||
return rejectedList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.klp.flowable.listener;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.klp.flowable.common.constant.ProcessConstants;
|
||||
import com.klp.flowable.common.enums.ProcessStatus;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Flowable 全局监听器
|
||||
*
|
||||
* @author konbai
|
||||
* @since 2023/3/8 22:45
|
||||
*/
|
||||
@Component
|
||||
public class GlobalEventListener extends AbstractFlowableEngineEventListener {
|
||||
|
||||
@Autowired
|
||||
private RuntimeService runtimeService;
|
||||
|
||||
/**
|
||||
* 流程结束监听器
|
||||
*/
|
||||
@Override
|
||||
protected void processCompleted(FlowableEngineEntityEvent event) {
|
||||
String processInstanceId = event.getProcessInstanceId();
|
||||
Object variable = runtimeService.getVariable(processInstanceId, ProcessConstants.PROCESS_STATUS_KEY);
|
||||
ProcessStatus status = ProcessStatus.getProcessStatus(Convert.toStr(variable));
|
||||
if (ObjectUtil.isNotNull(status) && ProcessStatus.RUNNING == status) {
|
||||
runtimeService.setVariable(processInstanceId, ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.COMPLETED.getStatus());
|
||||
}
|
||||
super.processCompleted(event);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.klp.flowable.listener;
|
||||
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 用户任务监听器
|
||||
*
|
||||
* @author KonBAI
|
||||
* @since 2023/5/13
|
||||
*/
|
||||
@Component(value = "userTaskListener")
|
||||
public class UserTaskListener implements TaskListener {
|
||||
|
||||
/**
|
||||
* 注入字段(名称与流程设计时字段名称一致)
|
||||
*/
|
||||
// private FixedValue field;
|
||||
|
||||
@Override
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
System.out.println("执行任务监听器...");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,373 +0,0 @@
|
||||
package com.klp.flowable.utils;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.common.engine.impl.util.io.StringStreamSource;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/26 19:04
|
||||
*/
|
||||
public class ModelUtils {
|
||||
|
||||
private static final BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
|
||||
|
||||
/**
|
||||
* xml转bpmnModel对象
|
||||
*
|
||||
* @param xml xml
|
||||
* @return bpmnModel对象
|
||||
*/
|
||||
public static BpmnModel getBpmnModel(String xml) {
|
||||
return bpmnXMLConverter.convertToBpmnModel(new StringStreamSource(xml), false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* bpmnModel转xml字符串
|
||||
*
|
||||
* @deprecated 存在会丢失 bpmn 连线问题
|
||||
* @param bpmnModel bpmnModel对象
|
||||
* @return xml字符串
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getBpmnXmlStr(BpmnModel bpmnModel) {
|
||||
return StrUtil.utf8Str(getBpmnXml(bpmnModel));
|
||||
}
|
||||
|
||||
/**
|
||||
* bpmnModel转xml对象
|
||||
*
|
||||
* @deprecated 存在丢失 bpmn 连线问题
|
||||
* @param bpmnModel bpmnModel对象
|
||||
* @return xml
|
||||
*/
|
||||
@Deprecated
|
||||
public static byte[] getBpmnXml(BpmnModel bpmnModel) {
|
||||
return bpmnXMLConverter.convertToXML(bpmnModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据节点,获取入口连线
|
||||
*
|
||||
* @param source 起始节点
|
||||
* @return 入口连线列表
|
||||
*/
|
||||
public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
|
||||
List<SequenceFlow> sequenceFlows = new ArrayList<>();
|
||||
if (source instanceof FlowNode) {
|
||||
sequenceFlows = ((FlowNode) source).getIncomingFlows();
|
||||
}
|
||||
return sequenceFlows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据节点,获取出口连线
|
||||
*
|
||||
* @param source 起始节点
|
||||
* @return 出口连线列表
|
||||
*/
|
||||
public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
|
||||
List<SequenceFlow> sequenceFlows = new ArrayList<>();
|
||||
if (source instanceof FlowNode) {
|
||||
sequenceFlows = ((FlowNode) source).getOutgoingFlows();
|
||||
}
|
||||
return sequenceFlows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取开始节点
|
||||
*
|
||||
* @param model bpmnModel对象
|
||||
* @return 开始节点(未找到开始节点,返回null)
|
||||
*/
|
||||
public static StartEvent getStartEvent(BpmnModel model) {
|
||||
Process process = model.getMainProcess();
|
||||
FlowElement startElement = process.getInitialFlowElement();
|
||||
if (startElement instanceof StartEvent) {
|
||||
return (StartEvent) startElement;
|
||||
}
|
||||
return getStartEvent(process.getFlowElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取开始节点
|
||||
*
|
||||
* @param flowElements 流程元素集合
|
||||
* @return 开始节点(未找到开始节点,返回null)
|
||||
*/
|
||||
public static StartEvent getStartEvent(Collection<FlowElement> flowElements) {
|
||||
for (FlowElement flowElement : flowElements) {
|
||||
if (flowElement instanceof StartEvent) {
|
||||
return (StartEvent) flowElement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取结束节点
|
||||
*
|
||||
* @param model bpmnModel对象
|
||||
* @return 结束节点(未找到开始节点,返回null)
|
||||
*/
|
||||
public static EndEvent getEndEvent(BpmnModel model) {
|
||||
Process process = model.getMainProcess();
|
||||
return getEndEvent(process.getFlowElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取结束节点
|
||||
*
|
||||
* @param flowElements 流程元素集合
|
||||
* @return 结束节点(未找到开始节点,返回null)
|
||||
*/
|
||||
public static EndEvent getEndEvent(Collection<FlowElement> flowElements) {
|
||||
for (FlowElement flowElement : flowElements) {
|
||||
if (flowElement instanceof EndEvent) {
|
||||
return (EndEvent) flowElement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static UserTask getUserTaskByKey(BpmnModel model, String taskKey) {
|
||||
Process process = model.getMainProcess();
|
||||
FlowElement flowElement = process.getFlowElement(taskKey);
|
||||
if (flowElement instanceof UserTask) {
|
||||
return (UserTask) flowElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程元素信息
|
||||
*
|
||||
* @param model bpmnModel对象
|
||||
* @param flowElementId 元素ID
|
||||
* @return 元素信息
|
||||
*/
|
||||
public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
|
||||
Process process = model.getMainProcess();
|
||||
return process.getFlowElement(flowElementId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元素表单Key(限开始节点和用户节点可用)
|
||||
*
|
||||
* @param flowElement 元素
|
||||
* @return 表单Key
|
||||
*/
|
||||
public static String getFormKey(FlowElement flowElement) {
|
||||
if (flowElement != null) {
|
||||
if (flowElement instanceof StartEvent) {
|
||||
return ((StartEvent) flowElement).getFormKey();
|
||||
} else if (flowElement instanceof UserTask) {
|
||||
return ((UserTask) flowElement).getFormKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取开始节点属性值
|
||||
* @param model bpmnModel对象
|
||||
* @param name 属性名
|
||||
* @return 属性值
|
||||
*/
|
||||
public static String getStartEventAttributeValue(BpmnModel model, String name) {
|
||||
StartEvent startEvent = getStartEvent(model);
|
||||
return getElementAttributeValue(startEvent, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取结束节点属性值
|
||||
* @param model bpmnModel对象
|
||||
* @param name 属性名
|
||||
* @return 属性值
|
||||
*/
|
||||
public static String getEndEventAttributeValue(BpmnModel model, String name) {
|
||||
EndEvent endEvent = getEndEvent(model);
|
||||
return getElementAttributeValue(endEvent, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户任务节点属性值
|
||||
* @param model bpmnModel对象
|
||||
* @param taskKey 任务Key
|
||||
* @param name 属性名
|
||||
* @return 属性值
|
||||
*/
|
||||
public static String getUserTaskAttributeValue(BpmnModel model, String taskKey, String name) {
|
||||
UserTask userTask = getUserTaskByKey(model, taskKey);
|
||||
return getElementAttributeValue(userTask, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元素属性值
|
||||
* @param baseElement 流程元素
|
||||
* @param name 属性名
|
||||
* @return 属性值
|
||||
*/
|
||||
public static String getElementAttributeValue(BaseElement baseElement, String name) {
|
||||
if (baseElement != null) {
|
||||
List<ExtensionAttribute> attributes = baseElement.getAttributes().get(name);
|
||||
if (attributes != null && !attributes.isEmpty()) {
|
||||
attributes.iterator().next().getValue();
|
||||
Iterator<ExtensionAttribute> attrIterator = attributes.iterator();
|
||||
if(attrIterator.hasNext()) {
|
||||
ExtensionAttribute attribute = attrIterator.next();
|
||||
return attribute.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isMultiInstance(BpmnModel model, String taskKey) {
|
||||
UserTask userTask = getUserTaskByKey(model, taskKey);
|
||||
if (ObjectUtil.isNotNull(userTask)) {
|
||||
return userTask.hasMultiInstanceLoopCharacteristics();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有用户任务节点
|
||||
*
|
||||
* @param model bpmnModel对象
|
||||
* @return 用户任务节点列表
|
||||
*/
|
||||
public static Collection<UserTask> getAllUserTaskEvent(BpmnModel model) {
|
||||
Process process = model.getMainProcess();
|
||||
Collection<FlowElement> flowElements = process.getFlowElements();
|
||||
return getAllUserTaskEvent(flowElements, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有用户任务节点
|
||||
* @param flowElements 流程元素集合
|
||||
* @param allElements 所有流程元素集合
|
||||
* @return 用户任务节点列表
|
||||
*/
|
||||
public static Collection<UserTask> getAllUserTaskEvent(Collection<FlowElement> flowElements, Collection<UserTask> allElements) {
|
||||
allElements = allElements == null ? new ArrayList<>() : allElements;
|
||||
for (FlowElement flowElement : flowElements) {
|
||||
if (flowElement instanceof UserTask) {
|
||||
allElements.add((UserTask) flowElement);
|
||||
}
|
||||
if (flowElement instanceof SubProcess) {
|
||||
// 继续深入子流程,进一步获取子流程
|
||||
allElements = getAllUserTaskEvent(((SubProcess) flowElement).getFlowElements(), allElements);
|
||||
}
|
||||
}
|
||||
return allElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找起始节点下一个用户任务列表列表
|
||||
* @param source 起始节点
|
||||
* @return 结果
|
||||
*/
|
||||
public static List<UserTask> findNextUserTasks(FlowElement source) {
|
||||
return findNextUserTasks(source, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找起始节点下一个用户任务列表列表
|
||||
* @param source 起始节点
|
||||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @param userTaskList 用户任务列表
|
||||
* @return 结果
|
||||
*/
|
||||
public static List<UserTask> findNextUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
|
||||
hasSequenceFlow = Optional.ofNullable(hasSequenceFlow).orElse(new HashSet<>());
|
||||
userTaskList = Optional.ofNullable(userTaskList).orElse(new ArrayList<>());
|
||||
// 获取出口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||
if (!sequenceFlows.isEmpty()) {
|
||||
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
hasSequenceFlow.add(sequenceFlow.getId());
|
||||
FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
|
||||
if (targetFlowElement instanceof UserTask) {
|
||||
// 若节点为用户任务,加入到结果列表中
|
||||
userTaskList.add((UserTask) targetFlowElement);
|
||||
} else {
|
||||
// 若节点非用户任务,继续递归查找下一个节点
|
||||
findNextUserTasks(targetFlowElement, hasSequenceFlow, userTaskList);
|
||||
}
|
||||
}
|
||||
}
|
||||
return userTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
|
||||
* 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
|
||||
* @param source 起始节点
|
||||
* @param target 目标节点
|
||||
* @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) {
|
||||
visitedElements = visitedElements == null ? new HashSet<>() : visitedElements;
|
||||
if (source instanceof StartEvent && isInEventSubprocess(source)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 根据类型,获取入口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||
if (sequenceFlows != null && sequenceFlows.size() > 0) {
|
||||
// 循环找到目标元素
|
||||
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (visitedElements.contains(sequenceFlow.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
visitedElements.add(sequenceFlow.getId());
|
||||
FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
|
||||
// 这条线路存在目标节点,这条线路完成,进入下个线路
|
||||
if (target.getId().equals(sourceFlowElement.getId())) {
|
||||
continue;
|
||||
}
|
||||
// 如果目标节点为并行网关,则不继续
|
||||
if (sourceFlowElement instanceof ParallelGateway) {
|
||||
return false;
|
||||
}
|
||||
// 否则就继续迭代
|
||||
boolean isSequential = isSequentialReachable(sourceFlowElement, target, visitedElements);
|
||||
if (!isSequential) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static boolean isInEventSubprocess(FlowElement flowElement) {
|
||||
FlowElementsContainer flowElementsContainer = flowElement.getParentContainer();
|
||||
while (flowElementsContainer != null) {
|
||||
if (flowElementsContainer instanceof EventSubProcess) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (flowElementsContainer instanceof FlowElement) {
|
||||
flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer();
|
||||
} else {
|
||||
flowElementsContainer = null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.klp.flowable.utils;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.klp.flowable.core.FormConf;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程表单工具类
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/8/7 17:09
|
||||
*/
|
||||
public class ProcessFormUtils {
|
||||
|
||||
private static final String CONFIG = "__config__";
|
||||
private static final String MODEL = "__vModel__";
|
||||
|
||||
/**
|
||||
* 填充表单项内容
|
||||
*
|
||||
* @param formConf 表单配置信息
|
||||
* @param data 表单内容
|
||||
*/
|
||||
public static void fillFormData(FormConf formConf, Map<String, Object> data) {
|
||||
for (Map<String, Object> field : formConf.getFields()) {
|
||||
recursiveFillField(field, data);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void recursiveFillField(final Map<String, Object> field, final Map<String, Object> data) {
|
||||
if (!field.containsKey(CONFIG)) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> configMap = (Map<String, Object>) field.get(CONFIG);
|
||||
if (configMap.containsKey("children")) {
|
||||
List<Map<String, Object>> childrens = (List<Map<String, Object>>) configMap.get("children");
|
||||
for (Map<String, Object> children : childrens) {
|
||||
recursiveFillField(children, data);
|
||||
}
|
||||
}
|
||||
String modelKey = Convert.toStr(field.get(MODEL));
|
||||
Object value = data.get(modelKey);
|
||||
if (value != null) {
|
||||
configMap.put("defaultValue", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package com.klp.flowable.utils;
|
||||
|
||||
import com.klp.common.utils.DateUtils;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.flowable.core.domain.ProcessQuery;
|
||||
import org.flowable.common.engine.api.query.Query;
|
||||
import org.flowable.common.engine.impl.db.SuspensionState;
|
||||
import org.flowable.engine.history.HistoricProcessInstanceQuery;
|
||||
import org.flowable.engine.repository.ProcessDefinitionQuery;
|
||||
import org.flowable.task.api.TaskQuery;
|
||||
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程工具类
|
||||
*
|
||||
* @author konbai
|
||||
* @since 2022/12/11 03:35
|
||||
*/
|
||||
public class ProcessUtils {
|
||||
|
||||
public static void buildProcessSearch(Query<?, ?> query, ProcessQuery process) {
|
||||
if (query instanceof ProcessDefinitionQuery) {
|
||||
buildProcessDefinitionSearch((ProcessDefinitionQuery) query, process);
|
||||
} else if (query instanceof TaskQuery) {
|
||||
buildTaskSearch((TaskQuery) query, process);
|
||||
} else if (query instanceof HistoricTaskInstanceQuery) {
|
||||
buildHistoricTaskInstanceSearch((HistoricTaskInstanceQuery) query, process);
|
||||
} else if (query instanceof HistoricProcessInstanceQuery) {
|
||||
buildHistoricProcessInstanceSearch((HistoricProcessInstanceQuery) query, process);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建流程定义搜索
|
||||
*/
|
||||
public static void buildProcessDefinitionSearch(ProcessDefinitionQuery query, ProcessQuery process) {
|
||||
// 流程标识
|
||||
if (StringUtils.isNotBlank(process.getProcessKey())) {
|
||||
query.processDefinitionKeyLike("%" + process.getProcessKey() + "%");
|
||||
}
|
||||
// 流程名称
|
||||
if (StringUtils.isNotBlank(process.getProcessName())) {
|
||||
query.processDefinitionNameLike("%" + process.getProcessName() + "%");
|
||||
}
|
||||
// 流程分类
|
||||
if (StringUtils.isNotBlank(process.getCategory())) {
|
||||
query.processDefinitionCategory(process.getCategory());
|
||||
}
|
||||
// 流程状态
|
||||
if (StringUtils.isNotBlank(process.getState())) {
|
||||
if (SuspensionState.ACTIVE.toString().equals(process.getState())) {
|
||||
query.active();
|
||||
} else if (SuspensionState.SUSPENDED.toString().equals(process.getState())) {
|
||||
query.suspended();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建任务搜索
|
||||
*/
|
||||
public static void buildTaskSearch(TaskQuery query, ProcessQuery process) {
|
||||
Map<String, Object> params = process.getParams();
|
||||
if (StringUtils.isNotBlank(process.getProcessKey())) {
|
||||
query.processDefinitionKeyLike("%" + process.getProcessKey() + "%");
|
||||
}
|
||||
if (StringUtils.isNotBlank(process.getProcessName())) {
|
||||
query.processDefinitionNameLike("%" + process.getProcessName() + "%");
|
||||
}
|
||||
if (params.get("beginTime") != null && params.get("endTime") != null) {
|
||||
query.taskCreatedAfter(DateUtils.parseDate(params.get("beginTime")));
|
||||
query.taskCreatedBefore(DateUtils.parseDate(params.get("endTime")));
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildHistoricTaskInstanceSearch(HistoricTaskInstanceQuery query, ProcessQuery process) {
|
||||
Map<String, Object> params = process.getParams();
|
||||
if (StringUtils.isNotBlank(process.getProcessKey())) {
|
||||
query.processDefinitionKeyLike("%" + process.getProcessKey() + "%");
|
||||
}
|
||||
if (StringUtils.isNotBlank(process.getProcessName())) {
|
||||
query.processDefinitionNameLike("%" + process.getProcessName() + "%");
|
||||
}
|
||||
if (params.get("beginTime") != null && params.get("endTime") != null) {
|
||||
query.taskCompletedAfter(DateUtils.parseDate(params.get("beginTime")));
|
||||
query.taskCompletedBefore(DateUtils.parseDate(params.get("endTime")));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建历史流程实例搜索
|
||||
*/
|
||||
public static void buildHistoricProcessInstanceSearch(HistoricProcessInstanceQuery query, ProcessQuery process) {
|
||||
Map<String, Object> params = process.getParams();
|
||||
// 流程标识
|
||||
if (StringUtils.isNotBlank(process.getProcessKey())) {
|
||||
query.processDefinitionKey(process.getProcessKey());
|
||||
}
|
||||
// 流程名称
|
||||
if (StringUtils.isNotBlank(process.getProcessName())) {
|
||||
query.processDefinitionName(process.getProcessName());
|
||||
}
|
||||
// 流程名称
|
||||
if (StringUtils.isNotBlank(process.getCategory())) {
|
||||
query.processDefinitionCategory(process.getCategory());
|
||||
}
|
||||
if (params.get("beginTime") != null && params.get("endTime") != null) {
|
||||
query.startedAfter(DateUtils.parseDate(params.get("beginTime")));
|
||||
query.startedBefore(DateUtils.parseDate(params.get("endTime")));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.klp.flowable.utils;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.klp.common.core.domain.model.LoginUser;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.flowable.common.constant.TaskConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工作流任务工具类
|
||||
*
|
||||
* @author konbai
|
||||
* @createTime 2022/4/24 12:42
|
||||
*/
|
||||
public class TaskUtils {
|
||||
|
||||
public static String getUserId() {
|
||||
return String.valueOf(LoginHelper.getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户组信息
|
||||
*
|
||||
* @return candidateGroup
|
||||
*/
|
||||
public static List<String> getCandidateGroup() {
|
||||
List<String> list = new ArrayList<>();
|
||||
LoginUser user = LoginHelper.getLoginUser();
|
||||
if (ObjectUtil.isNotNull(user)) {
|
||||
if (ObjectUtil.isNotEmpty(user.getRoles())) {
|
||||
user.getRoles().forEach(role -> list.add(TaskConstants.ROLE_GROUP_PREFIX + role.getRoleId()));
|
||||
}
|
||||
if (ObjectUtil.isNotNull(user.getDeptId())) {
|
||||
list.add(TaskConstants.DEPT_GROUP_PREFIX + user.getDeptId());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -23,12 +23,6 @@
|
||||
<artifactId>klp-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Flowable功能模块 -->
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-flowable</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- OSS功能模块 -->
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.klp.workflow.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 流程分类对象 wf_category
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("wf_category")
|
||||
public class WfCategory extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
/**
|
||||
* 分类ID
|
||||
*/
|
||||
@TableId(value = "category_id")
|
||||
private Long categoryId;
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
@NotBlank(message = "分类名称不能为空")
|
||||
private String categoryName;
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
@NotBlank(message = "分类编码不能为空")
|
||||
private String code;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package com.klp.workflow.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 流程抄送对象 wf_copy
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-05-19
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("wf_copy")
|
||||
public class WfCopy extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
/**
|
||||
* 抄送主键
|
||||
*/
|
||||
@TableId(value = "copy_id")
|
||||
private Long copyId;
|
||||
/**
|
||||
* 抄送标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 流程主键
|
||||
*/
|
||||
private String processId;
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
private String processName;
|
||||
/**
|
||||
* 流程分类主键
|
||||
*/
|
||||
private String categoryId;
|
||||
/**
|
||||
* 部署主键
|
||||
*/
|
||||
private String deploymentId;
|
||||
/**
|
||||
* 流程实例主键
|
||||
*/
|
||||
private String instanceId;
|
||||
/**
|
||||
* 任务主键
|
||||
*/
|
||||
private String taskId;
|
||||
/**
|
||||
* 用户主键
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 发起人Id
|
||||
*/
|
||||
private Long originatorId;
|
||||
/**
|
||||
* 发起人名称
|
||||
*/
|
||||
private String originatorName;
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.klp.workflow.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程实例关联表单对象 sys_instance_form
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
@Data
|
||||
@TableName("wf_deploy_form")
|
||||
public class WfDeployForm {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程部署主键
|
||||
*/
|
||||
private String deployId;
|
||||
|
||||
/**
|
||||
* 表单Key
|
||||
*/
|
||||
private String formKey;
|
||||
|
||||
/**
|
||||
* 节点Key
|
||||
*/
|
||||
private String nodeKey;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
private String formName;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 表单内容
|
||||
*/
|
||||
private String content;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.klp.workflow.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 流程表单对象 wf_form
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("wf_form")
|
||||
public class WfForm extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 表单主键
|
||||
*/
|
||||
@TableId(value = "form_id")
|
||||
private Long formId;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
private String formName;
|
||||
|
||||
/**
|
||||
* 表单内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.klp.workflow.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 流程抄送业务对象 wf_copy
|
||||
*
|
||||
* @author klp
|
||||
* @date 2022-05-19
|
||||
*/
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class WfCopyBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 抄送主键
|
||||
*/
|
||||
@NotNull(message = "抄送主键不能为空", groups = { EditGroup.class })
|
||||
private Long copyId;
|
||||
|
||||
/**
|
||||
* 抄送标题
|
||||
*/
|
||||
@NotNull(message = "抄送标题不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 流程主键
|
||||
*/
|
||||
@NotBlank(message = "流程主键不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String processId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@NotBlank(message = "流程名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程分类主键
|
||||
*/
|
||||
@NotBlank(message = "流程分类主键不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String categoryId;
|
||||
|
||||
/**
|
||||
* 任务主键
|
||||
*/
|
||||
@NotBlank(message = "任务主键不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 用户主键
|
||||
*/
|
||||
@NotNull(message = "用户主键不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 发起人Id
|
||||
*/
|
||||
@NotNull(message = "发起人主键不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long originatorId;
|
||||
/**
|
||||
* 发起人名称
|
||||
*/
|
||||
@NotNull(message = "发起人名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String originatorName;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.klp.workflow.domain.bo;
|
||||
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 流程设计业务对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Data
|
||||
public class WfDesignerBo {
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@NotNull(message = "流程名称", groups = { AddGroup.class, EditGroup.class })
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 流程分类
|
||||
*/
|
||||
@NotBlank(message = "流程分类", groups = { AddGroup.class, EditGroup.class })
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* XML字符串
|
||||
*/
|
||||
@NotBlank(message = "XML字符串", groups = { AddGroup.class, EditGroup.class })
|
||||
private String xml;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.klp.workflow.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 流程表单业务对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class WfFormBo extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 表单主键
|
||||
*/
|
||||
@NotNull(message = "表单ID不能为空", groups = { EditGroup.class })
|
||||
private Long formId;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
@NotBlank(message = "表单名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String formName;
|
||||
|
||||
/**
|
||||
* 表单内容
|
||||
*/
|
||||
@NotBlank(message = "表单内容不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package com.klp.workflow.domain.bo;
|
||||
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 流程模型对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/21 9:16
|
||||
*/
|
||||
@Data
|
||||
public class WfModelBo {
|
||||
/**
|
||||
* 模型主键
|
||||
*/
|
||||
@NotNull(message = "模型主键不能为空", groups = { EditGroup.class })
|
||||
private String modelId;
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
@NotNull(message = "模型名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String modelName;
|
||||
/**
|
||||
* 模型Key
|
||||
*/
|
||||
@NotNull(message = "模型Key不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String modelKey;
|
||||
/**
|
||||
* 流程分类
|
||||
*/
|
||||
@NotBlank(message = "流程分类不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String category;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 表单类型
|
||||
*/
|
||||
private Integer formType;
|
||||
/**
|
||||
* 表单主键
|
||||
*/
|
||||
private Long formId;
|
||||
/**
|
||||
* 流程xml
|
||||
*/
|
||||
private String bpmnXml;
|
||||
/**
|
||||
* 是否保存为新版本
|
||||
*/
|
||||
private Boolean newVersion;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package com.klp.workflow.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程任务业务对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Data
|
||||
public class WfTaskBo {
|
||||
/**
|
||||
* 任务Id
|
||||
*/
|
||||
private String taskId;
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
private String taskName;
|
||||
/**
|
||||
* 用户Id
|
||||
*/
|
||||
private String userId;
|
||||
/**
|
||||
* 任务意见
|
||||
*/
|
||||
private String comment;
|
||||
/**
|
||||
* 流程实例Id
|
||||
*/
|
||||
private String procInsId;
|
||||
/**
|
||||
* 节点
|
||||
*/
|
||||
private String targetKey;
|
||||
/**
|
||||
* 流程变量信息
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
/**
|
||||
* 审批人
|
||||
*/
|
||||
private String assignee;
|
||||
/**
|
||||
* 候选人
|
||||
*/
|
||||
private List<String> candidateUsers;
|
||||
/**
|
||||
* 审批组
|
||||
*/
|
||||
private List<String> candidateGroups;
|
||||
/**
|
||||
* 抄送用户Id
|
||||
*/
|
||||
private String copyUserIds;
|
||||
/**
|
||||
* 下一节点审批人
|
||||
*/
|
||||
private String nextUserIds;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.klp.workflow.domain.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class WfCommentDto implements Serializable {
|
||||
|
||||
/**
|
||||
* 意见类别 0 正常意见 1 退回意见 2 驳回意见
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 意见内容
|
||||
*/
|
||||
private String comment;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.klp.workflow.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/21 9:16
|
||||
*/
|
||||
@Data
|
||||
public class WfMetaInfoDto {
|
||||
|
||||
/**
|
||||
* 创建者(username)
|
||||
*/
|
||||
private String createUser;
|
||||
|
||||
/**
|
||||
* 流程描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 表单类型
|
||||
*/
|
||||
private Integer formType;
|
||||
/**
|
||||
* 表单编号
|
||||
*/
|
||||
private Long formId;
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.klp.workflow.domain.dto;
|
||||
|
||||
import com.klp.common.core.domain.entity.SysRole;
|
||||
import com.klp.common.core.domain.entity.SysUser;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 动态人员、组
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Data
|
||||
public class WfNextDto implements Serializable {
|
||||
|
||||
private String type;
|
||||
|
||||
private String vars;
|
||||
|
||||
private List<SysUser> userList;
|
||||
|
||||
private List<SysRole> roleList;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 流程分类视图对象 flow_category
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-01-15
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfCategoryVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 分类ID
|
||||
*/
|
||||
@ExcelProperty(value = "分类ID")
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
@ExcelProperty(value = "分类名称")
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
@ExcelProperty(value = "分类编码")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 待签流程对象导出VO
|
||||
*
|
||||
* @author konbai
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WfClaimTaskExportVo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务编号
|
||||
*/
|
||||
@ExcelProperty(value = "任务编号")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String procDefName;
|
||||
|
||||
/**
|
||||
* 任务节点
|
||||
*/
|
||||
@ExcelProperty(value = "任务节点")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 流程版本
|
||||
*/
|
||||
@ExcelProperty(value = "流程版本")
|
||||
private int procDefVersion;
|
||||
|
||||
/**
|
||||
* 流程发起人名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程发起人")
|
||||
private String startUserName;
|
||||
|
||||
/**
|
||||
* 接收时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ExcelProperty(value = "接收时间")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程批复视图对象
|
||||
*
|
||||
* @author konbai
|
||||
* @createTime 2022/4/4 02:03
|
||||
*/
|
||||
@Data
|
||||
public class WfCommentVo {
|
||||
|
||||
/**
|
||||
* 审批类别
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 批复内容
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 批复时间
|
||||
*/
|
||||
private Date time;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 流程抄送视图对象 wf_copy
|
||||
*
|
||||
* @author klp
|
||||
* @date 2022-05-19
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfCopyVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 抄送主键
|
||||
*/
|
||||
@ExcelProperty(value = "抄送主键")
|
||||
private Long copyId;
|
||||
|
||||
/**
|
||||
* 抄送标题
|
||||
*/
|
||||
@ExcelProperty(value = "抄送标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 流程主键
|
||||
*/
|
||||
@ExcelProperty(value = "流程主键")
|
||||
private String processId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程分类主键
|
||||
*/
|
||||
@ExcelProperty(value = "流程分类主键")
|
||||
private String categoryId;
|
||||
|
||||
/**
|
||||
* 部署主键
|
||||
*/
|
||||
@ExcelProperty(value = "部署主键")
|
||||
private String deploymentId;
|
||||
|
||||
/**
|
||||
* 流程实例主键
|
||||
*/
|
||||
@ExcelProperty(value = "流程实例主键")
|
||||
private String instanceId;
|
||||
|
||||
/**
|
||||
* 任务主键
|
||||
*/
|
||||
@ExcelProperty(value = "任务主键")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 用户主键
|
||||
*/
|
||||
@ExcelProperty(value = "用户主键")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 发起人Id
|
||||
*/
|
||||
@ExcelProperty(value = "发起人主键")
|
||||
private Long originatorId;
|
||||
|
||||
/**
|
||||
* 发起人名称
|
||||
*/
|
||||
@ExcelProperty(value = "发起人名称")
|
||||
private String originatorName;
|
||||
|
||||
/**
|
||||
* 抄送时间(创建时间)
|
||||
*/
|
||||
@ExcelProperty(value = "抄送时间")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.klp.common.annotation.ExcelDictFormat;
|
||||
import com.klp.common.convert.ExcelDictConvert;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 流程定义视图对象 workflow_definition
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-01-17
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfDefinitionVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程定义ID
|
||||
*/
|
||||
@ExcelProperty(value = "流程定义ID")
|
||||
private String definitionId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程Key
|
||||
*/
|
||||
@ExcelProperty(value = "流程Key")
|
||||
private String processKey;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
@ExcelProperty(value = "分类编码")
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
@ExcelProperty(value = "版本")
|
||||
private Integer version;
|
||||
|
||||
/**
|
||||
* 表单ID
|
||||
*/
|
||||
@ExcelProperty(value = "表单ID")
|
||||
private Long formId;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
@ExcelProperty(value = "表单名称")
|
||||
private String formName;
|
||||
|
||||
/**
|
||||
* 部署ID
|
||||
*/
|
||||
@ExcelProperty(value = "部署ID")
|
||||
private String deploymentId;
|
||||
|
||||
/**
|
||||
* 流程是否暂停(true:挂起 false:激活 )
|
||||
*/
|
||||
@ExcelProperty(value = "流程是否挂起", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "true=挂起,false=激活")
|
||||
private Boolean suspended;
|
||||
|
||||
/**
|
||||
* 部署时间
|
||||
*/
|
||||
@ExcelProperty(value = "部署时间")
|
||||
private Date deploymentTime;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 部署实例和表单关联视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/7/17 18:29
|
||||
*/
|
||||
@Data
|
||||
public class WfDeployFormVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程部署主键
|
||||
*/
|
||||
private String deployId;
|
||||
|
||||
/**
|
||||
* 表单Key
|
||||
*/
|
||||
private String formKey;
|
||||
|
||||
/**
|
||||
* 节点Key
|
||||
*/
|
||||
private String nodeKey;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
private String formName;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 表单内容
|
||||
*/
|
||||
private String content;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 流程部署视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-06-30
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfDeployVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程定义ID
|
||||
*/
|
||||
@ExcelProperty(value = "流程定义ID")
|
||||
private String definitionId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程Key
|
||||
*/
|
||||
@ExcelProperty(value = "流程Key")
|
||||
private String processKey;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
@ExcelProperty(value = "分类编码")
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
private Integer version;
|
||||
|
||||
/**
|
||||
* 表单ID
|
||||
*/
|
||||
@ExcelProperty(value = "表单ID")
|
||||
private Long formId;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
@ExcelProperty(value = "表单名称")
|
||||
private String formName;
|
||||
|
||||
/**
|
||||
* 部署ID
|
||||
*/
|
||||
@ExcelProperty(value = "部署ID")
|
||||
private String deploymentId;
|
||||
|
||||
/**
|
||||
* 流程定义状态: 1:激活 , 2:中止
|
||||
*/
|
||||
@ExcelProperty(value = "流程定义状态: 1:激活 , 2:中止")
|
||||
private Boolean suspended;
|
||||
|
||||
/**
|
||||
* 部署时间
|
||||
*/
|
||||
@ExcelProperty(value = "部署时间")
|
||||
private Date deploymentTime;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.klp.flowable.core.FormConf;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程详情视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/8/7 15:01
|
||||
*/
|
||||
@Data
|
||||
public class WfDetailVo {
|
||||
|
||||
/**
|
||||
* 任务表单信息
|
||||
*/
|
||||
private FormConf taskFormData;
|
||||
|
||||
/**
|
||||
* 历史流程节点信息
|
||||
*/
|
||||
private List<WfProcNodeVo> historyProcNodeList;
|
||||
|
||||
/**
|
||||
* 流程表单列表
|
||||
*/
|
||||
private List<FormConf> processFormList;
|
||||
|
||||
/**
|
||||
* 流程XML
|
||||
*/
|
||||
private String bpmnXml;
|
||||
|
||||
private WfViewerVo flowViewer;
|
||||
|
||||
/**
|
||||
* 是否存在任务表单信息
|
||||
* @return true:存在;false:不存在
|
||||
*/
|
||||
public Boolean isExistTaskForm() {
|
||||
return ObjectUtil.isNotEmpty(this.taskFormData);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 已办流程对象导出VO
|
||||
*
|
||||
* @author konbai
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WfFinishedTaskExportVo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务编号
|
||||
*/
|
||||
@ExcelProperty(value = "任务编号")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String procDefName;
|
||||
|
||||
/**
|
||||
* 任务节点
|
||||
*/
|
||||
@ExcelProperty(value = "任务节点")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 流程版本
|
||||
*/
|
||||
@ExcelProperty(value = "流程版本")
|
||||
private int procDefVersion;
|
||||
|
||||
/**
|
||||
* 流程发起人名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程发起人")
|
||||
private String startUserName;
|
||||
|
||||
/**
|
||||
* 接收时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ExcelProperty(value = "接收时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ExcelProperty(value = "审批时间")
|
||||
private Date finishTime;
|
||||
|
||||
/**
|
||||
* 任务耗时
|
||||
*/
|
||||
@ExcelProperty(value = "任务耗时")
|
||||
private String duration;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程分类视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfFormVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 表单主键
|
||||
*/
|
||||
@ExcelProperty(value = "表单ID")
|
||||
private Long formId;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
@ExcelProperty(value = "表单名称")
|
||||
private String formName;
|
||||
|
||||
/**
|
||||
* 表单内容
|
||||
*/
|
||||
@ExcelProperty(value = "表单内容")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程模型对象导出VO
|
||||
*
|
||||
* @author konbai
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WfModelExportVo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 模型ID
|
||||
*/
|
||||
@ExcelProperty(value = "模型ID")
|
||||
private String modelId;
|
||||
/**
|
||||
* 模型Key
|
||||
*/
|
||||
@ExcelProperty(value = "模型Key")
|
||||
private String modelKey;
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
@ExcelProperty(value = "模型名称")
|
||||
private String modelName;
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
@ExcelProperty(value = "分类编码")
|
||||
private String category;
|
||||
/**
|
||||
* 流程分类
|
||||
*/
|
||||
@ExcelProperty(value = "流程分类")
|
||||
private String categoryName;
|
||||
/**
|
||||
* 模型版本
|
||||
*/
|
||||
@ExcelProperty(value = "模型版本")
|
||||
private Integer version;
|
||||
/**
|
||||
* 模型描述
|
||||
*/
|
||||
@ExcelProperty(value = "模型描述")
|
||||
private String description;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程模型视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/21 9:16
|
||||
*/
|
||||
@Data
|
||||
public class WfModelVo {
|
||||
/**
|
||||
* 模型ID
|
||||
*/
|
||||
private String modelId;
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String modelName;
|
||||
/**
|
||||
* 模型Key
|
||||
*/
|
||||
private String modelKey;
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
private String category;
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
private Integer version;
|
||||
/**
|
||||
* 表单类型
|
||||
*/
|
||||
private Integer formType;
|
||||
/**
|
||||
* 表单ID
|
||||
*/
|
||||
private Long formId;
|
||||
/**
|
||||
* 模型描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
/**
|
||||
* 流程xml
|
||||
*/
|
||||
private String bpmnXml;
|
||||
/**
|
||||
* 表单内容
|
||||
*/
|
||||
private String content;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 我拥有流程对象导出VO
|
||||
*
|
||||
* @author konbai
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WfOwnTaskExportVo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程实例ID
|
||||
*/
|
||||
@ExcelProperty(value = "流程编号")
|
||||
private String procInsId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String procDefName;
|
||||
|
||||
/**
|
||||
* 流程类别
|
||||
*/
|
||||
@ExcelProperty(value = "流程类别")
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 流程版本
|
||||
*/
|
||||
@ExcelProperty(value = "流程版本")
|
||||
private int procDefVersion;
|
||||
|
||||
/**
|
||||
* 提交时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ExcelProperty(value = "提交时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
@ExcelProperty(value = "流程状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 任务耗时
|
||||
*/
|
||||
@ExcelProperty(value = "任务耗时")
|
||||
private String duration;
|
||||
|
||||
/**
|
||||
* 当前节点
|
||||
*/
|
||||
@ExcelProperty(value = "当前节点")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 任务完成时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date finishTime;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.flowable.engine.task.Comment;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工作流节点元素视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/9/11 22:04
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfProcNodeVo implements Serializable {
|
||||
/**
|
||||
* 流程ID
|
||||
*/
|
||||
private String procDefId;
|
||||
/**
|
||||
* 活动ID
|
||||
*/
|
||||
private String activityId;
|
||||
/**
|
||||
* 活动名称
|
||||
*/
|
||||
private String activityName;
|
||||
/**
|
||||
* 活动类型
|
||||
*/
|
||||
private String activityType;
|
||||
/**
|
||||
* 活动耗时
|
||||
*/
|
||||
private String duration;
|
||||
/**
|
||||
* 执行人Id
|
||||
*/
|
||||
private Long assigneeId;
|
||||
/**
|
||||
* 执行人名称
|
||||
*/
|
||||
private String assigneeName;
|
||||
/**
|
||||
* 候选执行人
|
||||
*/
|
||||
private String candidate;
|
||||
/**
|
||||
* 任务意见
|
||||
*/
|
||||
private List<Comment> commentList;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.klp.workflow.domain.dto.WfCommentDto;
|
||||
import lombok.Data;
|
||||
import org.flowable.engine.task.Comment;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工作流任务视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfTaskVo implements Serializable {
|
||||
/**
|
||||
* 任务编号
|
||||
*/
|
||||
private String taskId;
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
private String taskName;
|
||||
/**
|
||||
* 任务Key
|
||||
*/
|
||||
private String taskDefKey;
|
||||
/**
|
||||
* 任务执行人Id
|
||||
*/
|
||||
private Long assigneeId;
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@Deprecated
|
||||
private String deptName;
|
||||
/**
|
||||
* 流程发起人部门名称
|
||||
*/
|
||||
@Deprecated
|
||||
private String startDeptName;
|
||||
/**
|
||||
* 任务执行人名称
|
||||
*/
|
||||
private String assigneeName;
|
||||
/**
|
||||
* 流程发起人Id
|
||||
*/
|
||||
private Long startUserId;
|
||||
/**
|
||||
* 流程发起人名称
|
||||
*/
|
||||
private String startUserName;
|
||||
/**
|
||||
* 流程类型
|
||||
*/
|
||||
private String category;
|
||||
/**
|
||||
* 流程变量信息
|
||||
*/
|
||||
private Object procVars;
|
||||
/**
|
||||
* 局部变量信息
|
||||
*/
|
||||
private Object taskLocalVars;
|
||||
/**
|
||||
* 流程部署编号
|
||||
*/
|
||||
private String deployId;
|
||||
/**
|
||||
* 流程ID
|
||||
*/
|
||||
private String procDefId;
|
||||
/**
|
||||
* 流程key
|
||||
*/
|
||||
private String procDefKey;
|
||||
/**
|
||||
* 流程定义名称
|
||||
*/
|
||||
private String procDefName;
|
||||
/**
|
||||
* 流程定义内置使用版本
|
||||
*/
|
||||
private int procDefVersion;
|
||||
/**
|
||||
* 流程实例ID
|
||||
*/
|
||||
private String procInsId;
|
||||
/**
|
||||
* 历史流程实例ID
|
||||
*/
|
||||
private String hisProcInsId;
|
||||
/**
|
||||
* 任务耗时
|
||||
*/
|
||||
private String duration;
|
||||
/**
|
||||
* 任务意见
|
||||
*/
|
||||
private WfCommentDto comment;
|
||||
/**
|
||||
* 任务意见
|
||||
*/
|
||||
private List<Comment> commentList;
|
||||
/**
|
||||
* 候选执行人
|
||||
*/
|
||||
private String candidate;
|
||||
/**
|
||||
* 任务创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
/**
|
||||
* 任务完成时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date finishTime;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
private String processStatus;
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 待办流程对象导出VO
|
||||
*
|
||||
* @author konbai
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WfTodoTaskExportVo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务编号
|
||||
*/
|
||||
@ExcelProperty(value = "任务编号")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String procDefName;
|
||||
|
||||
/**
|
||||
* 任务节点
|
||||
*/
|
||||
@ExcelProperty(value = "任务节点")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 流程版本
|
||||
*/
|
||||
@ExcelProperty(value = "流程版本")
|
||||
private int procDefVersion;
|
||||
|
||||
/**
|
||||
* 流程发起人名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程发起人")
|
||||
private String startUserName;
|
||||
|
||||
/**
|
||||
* 接收时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ExcelProperty(value = "接收时间")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.klp.workflow.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 任务追踪视图对象
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/1/8 19:42
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ExcelIgnoreUnannotated
|
||||
public class WfViewerVo {
|
||||
|
||||
/**
|
||||
* 获取流程实例的历史节点(去重)
|
||||
*/
|
||||
private Set<String> finishedTaskSet;
|
||||
|
||||
/**
|
||||
* 已完成
|
||||
*/
|
||||
private Set<String> finishedSequenceFlowSet;
|
||||
|
||||
/**
|
||||
* 获取流程实例当前正在待办的节点(去重)
|
||||
*/
|
||||
private Set<String> unfinishedTaskSet;
|
||||
|
||||
/**
|
||||
* 已拒绝
|
||||
*/
|
||||
private Set<String> rejectedTaskSet;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.klp.workflow.handler;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
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.toolkit.SimpleQuery;
|
||||
import com.klp.common.core.domain.entity.SysUser;
|
||||
import com.klp.flowable.common.constant.ProcessConstants;
|
||||
import com.klp.system.domain.SysUserRole;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 多实例处理类
|
||||
*
|
||||
* @author KonBAI
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Component("multiInstanceHandler")
|
||||
public class MultiInstanceHandler {
|
||||
|
||||
public Set<String> getUserIds(DelegateExecution execution) {
|
||||
Set<String> candidateUserIds = new LinkedHashSet<>();
|
||||
FlowElement flowElement = execution.getCurrentFlowElement();
|
||||
if (ObjectUtil.isNotEmpty(flowElement) && flowElement instanceof UserTask) {
|
||||
UserTask userTask = (UserTask) flowElement;
|
||||
String dataType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_DATA_TYPE);
|
||||
if ("USERS".equals(dataType) && CollUtil.isNotEmpty(userTask.getCandidateUsers())) {
|
||||
// 添加候选用户id
|
||||
candidateUserIds.addAll(userTask.getCandidateUsers());
|
||||
} else if (CollUtil.isNotEmpty(userTask.getCandidateGroups())) {
|
||||
// 获取组的ID,角色ID集合或部门ID集合
|
||||
List<Long> groups = userTask.getCandidateGroups().stream()
|
||||
.map(item -> Long.parseLong(item.substring(4)))
|
||||
.collect(Collectors.toList());
|
||||
List<Long> userIds = new ArrayList<>();
|
||||
if ("ROLES".equals(dataType)) {
|
||||
// 通过角色id,获取所有用户id集合
|
||||
LambdaQueryWrapper<SysUserRole> lqw = Wrappers.lambdaQuery(SysUserRole.class).select(SysUserRole::getUserId).in(SysUserRole::getRoleId, groups);
|
||||
userIds = SimpleQuery.list(lqw, SysUserRole::getUserId);
|
||||
} else if ("DEPTS".equals(dataType)) {
|
||||
// 通过部门id,获取所有用户id集合
|
||||
LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery(SysUser.class).select(SysUser::getUserId).in(SysUser::getDeptId, groups);
|
||||
userIds = SimpleQuery.list(lqw, SysUser::getUserId);
|
||||
}
|
||||
// 添加候选用户id
|
||||
userIds.forEach(id -> candidateUserIds.add(String.valueOf(id)));
|
||||
}
|
||||
}
|
||||
return candidateUserIds;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.klp.workflow.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.workflow.domain.WfCategory;
|
||||
import com.klp.workflow.domain.vo.WfCategoryVo;
|
||||
|
||||
/**
|
||||
* 流程分类Mapper接口
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-01-15
|
||||
*/
|
||||
public interface WfCategoryMapper extends BaseMapperPlus<WfCategoryMapper, WfCategory, WfCategoryVo> {
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.klp.workflow.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.workflow.domain.WfCopy;
|
||||
import com.klp.workflow.domain.vo.WfCopyVo;
|
||||
|
||||
/**
|
||||
* 流程抄送Mapper接口
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-05-19
|
||||
*/
|
||||
public interface WfCopyMapper extends BaseMapperPlus<WfCopyMapper, WfCopy, WfCopyVo> {
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.klp.workflow.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.workflow.domain.WfDeployForm;
|
||||
import com.klp.workflow.domain.vo.WfDeployFormVo;
|
||||
|
||||
/**
|
||||
* 流程实例关联表单Mapper接口
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
public interface WfDeployFormMapper extends BaseMapperPlus<WfDeployFormMapper, WfDeployForm, WfDeployFormVo> {
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.klp.workflow.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.workflow.domain.WfForm;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程表单Mapper接口
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
public interface WfFormMapper extends BaseMapperPlus<WfFormMapper, WfForm, WfFormVo> {
|
||||
|
||||
List<WfFormVo> selectFormVoList(@Param(Constants.WRAPPER) Wrapper<WfForm> queryWrapper);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.workflow.domain.WfCategory;
|
||||
import com.klp.workflow.domain.vo.WfCategoryVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程分类Service接口
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-01-15
|
||||
*/
|
||||
public interface IWfCategoryService {
|
||||
/**
|
||||
* 查询单个
|
||||
* @return
|
||||
*/
|
||||
WfCategoryVo queryById(Long categoryId);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
TableDataInfo<WfCategoryVo> queryPageList(WfCategory category, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
List<WfCategoryVo> queryList(WfCategory category);
|
||||
|
||||
/**
|
||||
* 新增流程分类
|
||||
*
|
||||
* @param category 流程分类信息
|
||||
* @return 结果
|
||||
*/
|
||||
int insertCategory(WfCategory category);
|
||||
|
||||
/**
|
||||
* 编辑流程分类
|
||||
* @param category 流程分类信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updateCategory(WfCategory category);
|
||||
|
||||
/**
|
||||
* 校验并删除数据
|
||||
* @param ids 主键集合
|
||||
* @param isValid 是否校验,true-删除前校验,false-不校验
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 校验分类编码是否唯一
|
||||
*
|
||||
* @param category 流程分类
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkCategoryCodeUnique(WfCategory category);
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.workflow.domain.bo.WfCopyBo;
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import com.klp.workflow.domain.vo.WfCopyVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程抄送Service接口
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-05-19
|
||||
*/
|
||||
public interface IWfCopyService {
|
||||
|
||||
/**
|
||||
* 查询流程抄送
|
||||
*
|
||||
* @param copyId 流程抄送主键
|
||||
* @return 流程抄送
|
||||
*/
|
||||
WfCopyVo queryById(Long copyId);
|
||||
|
||||
/**
|
||||
* 查询流程抄送列表
|
||||
*
|
||||
* @param wfCopy 流程抄送
|
||||
* @return 流程抄送集合
|
||||
*/
|
||||
TableDataInfo<WfCopyVo> selectPageList(WfCopyBo wfCopy, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询流程抄送列表
|
||||
*
|
||||
* @param wfCopy 流程抄送
|
||||
* @return 流程抄送集合
|
||||
*/
|
||||
List<WfCopyVo> selectList(WfCopyBo wfCopy);
|
||||
|
||||
/**
|
||||
* 抄送
|
||||
* @param taskBo
|
||||
* @return
|
||||
*/
|
||||
Boolean makeCopy(WfTaskBo taskBo);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.workflow.domain.WfDeployForm;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
|
||||
/**
|
||||
* 流程实例关联表单Service接口
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
public interface IWfDeployFormService {
|
||||
|
||||
/**
|
||||
* 新增流程实例关联表单
|
||||
*
|
||||
* @param wfDeployForm 流程实例关联表单
|
||||
* @return 结果
|
||||
*/
|
||||
int insertWfDeployForm(WfDeployForm wfDeployForm);
|
||||
|
||||
/**
|
||||
* 保存流程实例关联表单
|
||||
* @param deployId 部署ID
|
||||
* @param bpmnModel bpmnModel对象
|
||||
* @return
|
||||
*/
|
||||
boolean saveInternalDeployForm(String deployId, BpmnModel bpmnModel);
|
||||
|
||||
/**
|
||||
* 查询流程挂着的表单
|
||||
*
|
||||
* @param deployId
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
WfFormVo selectDeployFormByDeployId(String deployId);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.flowable.core.domain.ProcessQuery;
|
||||
import com.klp.workflow.domain.vo.WfDeployVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/30 9:03
|
||||
*/
|
||||
public interface IWfDeployService {
|
||||
|
||||
TableDataInfo<WfDeployVo> queryPageList(ProcessQuery processQuery, PageQuery pageQuery);
|
||||
|
||||
TableDataInfo<WfDeployVo> queryPublishList(String processKey, PageQuery pageQuery);
|
||||
|
||||
void updateState(String definitionId, String stateCode);
|
||||
|
||||
String queryBpmnXmlById(String definitionId);
|
||||
|
||||
void deleteByIds(List<String> deployIds);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.workflow.domain.bo.WfFormBo;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表单
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
public interface IWfFormService {
|
||||
/**
|
||||
* 查询流程表单
|
||||
*
|
||||
* @param formId 流程表单ID
|
||||
* @return 流程表单
|
||||
*/
|
||||
WfFormVo queryById(Long formId);
|
||||
|
||||
/**
|
||||
* 查询流程表单列表
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 流程表单集合
|
||||
*/
|
||||
TableDataInfo<WfFormVo> queryPageList(WfFormBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询流程表单列表
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 流程表单集合
|
||||
*/
|
||||
List<WfFormVo> queryList(WfFormBo bo);
|
||||
|
||||
/**
|
||||
* 新增流程表单
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 结果
|
||||
*/
|
||||
int insertForm(WfFormBo bo);
|
||||
|
||||
/**
|
||||
* 修改流程表单
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 结果
|
||||
*/
|
||||
int updateForm(WfFormBo bo);
|
||||
|
||||
/**
|
||||
* 批量删除流程表单
|
||||
*
|
||||
* @param formIds 需要删除的流程表单ID
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> formIds);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
public interface IWfInstanceService {
|
||||
|
||||
/**
|
||||
* 结束流程实例
|
||||
*
|
||||
* @param vo
|
||||
*/
|
||||
void stopProcessInstance(WfTaskBo vo);
|
||||
|
||||
/**
|
||||
* 激活或挂起流程实例
|
||||
*
|
||||
* @param state 状态
|
||||
* @param instanceId 流程实例ID
|
||||
*/
|
||||
void updateState(Integer state, String instanceId);
|
||||
|
||||
/**
|
||||
* 删除流程实例ID
|
||||
*
|
||||
* @param instanceId 流程实例ID
|
||||
* @param deleteReason 删除原因
|
||||
*/
|
||||
void delete(String instanceId, String deleteReason);
|
||||
|
||||
/**
|
||||
* 根据实例ID查询历史实例数据
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId);
|
||||
|
||||
|
||||
/**
|
||||
* 查询流程详情信息
|
||||
* @param procInsId 流程实例ID
|
||||
* @param deployId 流程部署ID
|
||||
*/
|
||||
Map<String, Object> queryDetailProcess(String procInsId, String deployId);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.workflow.domain.bo.WfModelBo;
|
||||
import com.klp.workflow.domain.vo.WfModelVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/21 9:11
|
||||
*/
|
||||
public interface IWfModelService {
|
||||
|
||||
/**
|
||||
* 查询流程模型列表
|
||||
*/
|
||||
TableDataInfo<WfModelVo> list(WfModelBo modelBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询流程模型列表
|
||||
*/
|
||||
List<WfModelVo> list(WfModelBo modelBo);
|
||||
|
||||
/**
|
||||
* 查询流程模型列表
|
||||
*/
|
||||
TableDataInfo<WfModelVo> historyList(WfModelBo modelBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询流程模型详情信息
|
||||
*/
|
||||
WfModelVo getModel(String modelId);
|
||||
|
||||
/**
|
||||
* 查询流程表单详细信息
|
||||
*/
|
||||
String queryBpmnXmlById(String modelId);
|
||||
|
||||
/**
|
||||
* 新增模型信息
|
||||
*/
|
||||
void insertModel(WfModelBo modelBo);
|
||||
|
||||
/**
|
||||
* 修改模型信息
|
||||
*/
|
||||
void updateModel(WfModelBo modelBo);
|
||||
|
||||
/**
|
||||
* 保存流程模型信息
|
||||
*/
|
||||
void saveModel(WfModelBo modelBo);
|
||||
|
||||
/**
|
||||
* 设为最新流程模型
|
||||
*/
|
||||
void latestModel(String modelId);
|
||||
|
||||
/**
|
||||
* 删除流程模型
|
||||
*/
|
||||
void deleteByIds(Collection<String> ids);
|
||||
|
||||
/**
|
||||
* 部署流程模型
|
||||
*/
|
||||
boolean deployModel(String modelId);
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.flowable.core.FormConf;
|
||||
import com.klp.flowable.core.domain.ProcessQuery;
|
||||
import com.klp.workflow.domain.vo.WfDefinitionVo;
|
||||
import com.klp.workflow.domain.vo.WfDetailVo;
|
||||
import com.klp.workflow.domain.vo.WfTaskVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/24 18:57
|
||||
*/
|
||||
public interface IWfProcessService {
|
||||
|
||||
/**
|
||||
* 查询可发起流程列表
|
||||
* @param pageQuery 分页参数
|
||||
* @return
|
||||
*/
|
||||
TableDataInfo<WfDefinitionVo> selectPageStartProcessList(ProcessQuery processQuery, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询可发起流程列表
|
||||
*/
|
||||
List<WfDefinitionVo> selectStartProcessList(ProcessQuery processQuery);
|
||||
|
||||
/**
|
||||
* 查询我的流程列表
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
TableDataInfo<WfTaskVo> selectPageOwnProcessList(ProcessQuery processQuery, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询我的流程列表
|
||||
*/
|
||||
List<WfTaskVo> selectOwnProcessList(ProcessQuery processQuery);
|
||||
|
||||
/**
|
||||
* 查询代办任务列表
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
TableDataInfo<WfTaskVo> selectPageTodoProcessList(ProcessQuery processQuery, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询代办任务列表
|
||||
*/
|
||||
List<WfTaskVo> selectTodoProcessList(ProcessQuery processQuery);
|
||||
|
||||
/**
|
||||
* 查询待签任务列表
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
TableDataInfo<WfTaskVo> selectPageClaimProcessList(ProcessQuery processQuery, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询待签任务列表
|
||||
*/
|
||||
List<WfTaskVo> selectClaimProcessList(ProcessQuery processQuery);
|
||||
|
||||
/**
|
||||
* 查询已办任务列表
|
||||
* @param pageQuery 分页参数
|
||||
*/
|
||||
TableDataInfo<WfTaskVo> selectPageFinishedProcessList(ProcessQuery processQuery, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询已办任务列表
|
||||
*/
|
||||
List<WfTaskVo> selectFinishedProcessList(ProcessQuery processQuery);
|
||||
|
||||
/**
|
||||
* 查询流程部署关联表单信息
|
||||
* @param definitionId 流程定义ID
|
||||
* @param deployId 部署ID
|
||||
*/
|
||||
FormConf selectFormContent(String definitionId, String deployId, String procInsId);
|
||||
|
||||
/**
|
||||
* 启动流程实例
|
||||
* @param procDefId 流程定义ID
|
||||
* @param variables 扩展参数
|
||||
*/
|
||||
void startProcessByDefId(String procDefId, Map<String, Object> variables);
|
||||
|
||||
/**
|
||||
* 通过DefinitionKey启动流程
|
||||
* @param procDefKey 流程定义Key
|
||||
* @param variables 扩展参数
|
||||
*/
|
||||
void startProcessByDefKey(String procDefKey, Map<String, Object> variables);
|
||||
|
||||
/**
|
||||
* 删除流程实例
|
||||
*/
|
||||
void deleteProcessByIds(String[] instanceIds);
|
||||
|
||||
|
||||
/**
|
||||
* 读取xml文件
|
||||
* @param processDefId 流程定义ID
|
||||
*/
|
||||
String queryBpmnXmlById(String processDefId);
|
||||
|
||||
|
||||
/**
|
||||
* 查询流程任务详情信息
|
||||
* @param procInsId 流程实例ID
|
||||
* @param taskId 任务ID
|
||||
*/
|
||||
WfDetailVo queryProcessDetail(String procInsId, String taskId);
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package com.klp.workflow.service;
|
||||
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
public interface IWfTaskService {
|
||||
|
||||
/**
|
||||
* 审批任务
|
||||
*
|
||||
* @param task 请求实体参数
|
||||
*/
|
||||
void complete(WfTaskBo task);
|
||||
|
||||
/**
|
||||
* 拒绝任务
|
||||
*
|
||||
* @param taskBo
|
||||
*/
|
||||
void taskReject(WfTaskBo taskBo);
|
||||
|
||||
|
||||
/**
|
||||
* 退回任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
void taskReturn(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 获取所有可回退的节点
|
||||
*
|
||||
* @param bo
|
||||
* @return
|
||||
*/
|
||||
List<FlowElement> findReturnTaskList(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
void deleteTask(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 认领/签收任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
void claim(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 取消认领/签收任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
void unClaim(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 委派任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
void delegateTask(WfTaskBo bo);
|
||||
|
||||
|
||||
/**
|
||||
* 转办任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
void transferTask(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 取消申请
|
||||
* @param bo
|
||||
* @return
|
||||
*/
|
||||
void stopProcess(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 撤回流程
|
||||
* @param bo
|
||||
* @return
|
||||
*/
|
||||
void revokeProcess(WfTaskBo bo);
|
||||
|
||||
/**
|
||||
* 获取流程过程图
|
||||
* @param processId
|
||||
* @return
|
||||
*/
|
||||
InputStream diagram(String processId);
|
||||
|
||||
/**
|
||||
* 获取流程变量
|
||||
* @param taskId 任务ID
|
||||
* @return 流程变量
|
||||
*/
|
||||
Map<String, Object> getProcessVariables(String taskId);
|
||||
|
||||
/**
|
||||
* 启动第一个任务
|
||||
* @param processInstance 流程实例
|
||||
* @param variables 流程参数
|
||||
*/
|
||||
void startFirstTask(ProcessInstance processInstance, Map<String, Object> variables);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
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 com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.workflow.domain.WfCategory;
|
||||
import com.klp.workflow.domain.vo.WfCategoryVo;
|
||||
import com.klp.workflow.mapper.WfCategoryMapper;
|
||||
import com.klp.workflow.service.IWfCategoryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程分类Service业务层处理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-01-15
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class WfCategoryServiceImpl implements IWfCategoryService {
|
||||
|
||||
private final WfCategoryMapper baseMapper;
|
||||
|
||||
@Override
|
||||
public WfCategoryVo queryById(Long categoryId){
|
||||
return baseMapper.selectVoById(categoryId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<WfCategoryVo> queryPageList(WfCategory category, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<WfCategory> lqw = buildQueryWrapper(category);
|
||||
Page<WfCategoryVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WfCategoryVo> queryList(WfCategory category) {
|
||||
LambdaQueryWrapper<WfCategory> lqw = buildQueryWrapper(category);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<WfCategory> buildQueryWrapper(WfCategory category) {
|
||||
Map<String, Object> params = category.getParams();
|
||||
LambdaQueryWrapper<WfCategory> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(category.getCategoryName()), WfCategory::getCategoryName, category.getCategoryName());
|
||||
lqw.eq(StringUtils.isNotBlank(category.getCode()), WfCategory::getCode, category.getCode());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertCategory(WfCategory categoryBo) {
|
||||
WfCategory add = BeanUtil.toBean(categoryBo, WfCategory.class);
|
||||
return baseMapper.insert(add);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCategory(WfCategory categoryBo) {
|
||||
WfCategory update = BeanUtil.toBean(categoryBo, WfCategory.class);
|
||||
return baseMapper.updateById(update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验分类编码是否唯一
|
||||
*
|
||||
* @param category 流程分类
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean checkCategoryCodeUnique(WfCategory category) {
|
||||
boolean exist = baseMapper.exists(new LambdaQueryWrapper<WfCategory>()
|
||||
.eq(WfCategory::getCode, category.getCode())
|
||||
.ne(ObjectUtil.isNotNull(category.getCategoryId()), WfCategory::getCategoryId, category.getCategoryId()));
|
||||
return !exist;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.workflow.domain.WfCopy;
|
||||
import com.klp.workflow.domain.bo.WfCopyBo;
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import com.klp.workflow.domain.vo.WfCopyVo;
|
||||
import com.klp.workflow.mapper.WfCopyMapper;
|
||||
import com.klp.workflow.service.IWfCopyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.flowable.engine.HistoryService;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程抄送Service业务层处理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @date 2022-05-19
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class WfCopyServiceImpl implements IWfCopyService {
|
||||
|
||||
private final WfCopyMapper baseMapper;
|
||||
|
||||
private final HistoryService historyService;
|
||||
|
||||
/**
|
||||
* 查询流程抄送
|
||||
*
|
||||
* @param copyId 流程抄送主键
|
||||
* @return 流程抄送
|
||||
*/
|
||||
@Override
|
||||
public WfCopyVo queryById(Long copyId){
|
||||
return baseMapper.selectVoById(copyId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程抄送列表
|
||||
*
|
||||
* @param bo 流程抄送
|
||||
* @return 流程抄送
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<WfCopyVo> selectPageList(WfCopyBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<WfCopy> lqw = buildQueryWrapper(bo);
|
||||
lqw.orderByDesc(WfCopy::getCreateTime);
|
||||
Page<WfCopyVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程抄送列表
|
||||
*
|
||||
* @param bo 流程抄送
|
||||
* @return 流程抄送
|
||||
*/
|
||||
@Override
|
||||
public List<WfCopyVo> selectList(WfCopyBo bo) {
|
||||
LambdaQueryWrapper<WfCopy> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<WfCopy> buildQueryWrapper(WfCopyBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<WfCopy> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getUserId() != null, WfCopy::getUserId, bo.getUserId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getProcessName()), WfCopy::getProcessName, bo.getProcessName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getOriginatorName()), WfCopy::getOriginatorName, bo.getOriginatorName());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean makeCopy(WfTaskBo taskBo) {
|
||||
if (StringUtils.isBlank(taskBo.getCopyUserIds())) {
|
||||
// 若抄送用户为空,则不需要处理,返回成功
|
||||
return true;
|
||||
}
|
||||
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
|
||||
.processInstanceId(taskBo.getProcInsId()).singleResult();
|
||||
String[] ids = taskBo.getCopyUserIds().split(",");
|
||||
List<WfCopy> copyList = new ArrayList<>(ids.length);
|
||||
Long originatorId = LoginHelper.getUserId();
|
||||
String originatorName = LoginHelper.getNickName();
|
||||
String title = historicProcessInstance.getProcessDefinitionName() + "-" + taskBo.getTaskName();
|
||||
for (String id : ids) {
|
||||
Long userId = Long.valueOf(id);
|
||||
WfCopy copy = new WfCopy();
|
||||
copy.setTitle(title);
|
||||
copy.setProcessId(historicProcessInstance.getProcessDefinitionId());
|
||||
copy.setProcessName(historicProcessInstance.getProcessDefinitionName());
|
||||
copy.setDeploymentId(historicProcessInstance.getDeploymentId());
|
||||
copy.setInstanceId(taskBo.getProcInsId());
|
||||
copy.setTaskId(taskBo.getTaskId());
|
||||
copy.setUserId(userId);
|
||||
copy.setOriginatorId(originatorId);
|
||||
copy.setOriginatorName(originatorName);
|
||||
copyList.add(copy);
|
||||
}
|
||||
return baseMapper.insertBatch(copyList);
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
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.toolkit.Wrappers;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.flowable.utils.ModelUtils;
|
||||
import com.klp.workflow.domain.WfDeployForm;
|
||||
import com.klp.workflow.domain.WfForm;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import com.klp.workflow.mapper.WfDeployFormMapper;
|
||||
import com.klp.workflow.mapper.WfFormMapper;
|
||||
import com.klp.workflow.service.IWfDeployFormService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FlowNode;
|
||||
import org.flowable.bpmn.model.StartEvent;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程实例关联表单Service业务层处理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class WfDeployFormServiceImpl implements IWfDeployFormService {
|
||||
|
||||
private final WfDeployFormMapper baseMapper;
|
||||
|
||||
private final WfFormMapper formMapper;
|
||||
|
||||
/**
|
||||
* 新增流程实例关联表单
|
||||
*
|
||||
* @param deployForm 流程实例关联表单
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int insertWfDeployForm(WfDeployForm deployForm) {
|
||||
// 删除部署流程和表单的关联关系
|
||||
baseMapper.delete(new LambdaQueryWrapper<WfDeployForm>().eq(WfDeployForm::getDeployId, deployForm.getDeployId()));
|
||||
// 新增部署流程和表单关系
|
||||
return baseMapper.insert(deployForm);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean saveInternalDeployForm(String deployId, BpmnModel bpmnModel) {
|
||||
List<WfDeployForm> deployFormList = new ArrayList<>();
|
||||
// 获取开始节点
|
||||
StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
|
||||
if (ObjectUtil.isNull(startEvent)) {
|
||||
throw new RuntimeException("开始节点不存在,请检查流程设计是否有误!");
|
||||
}
|
||||
// 保存开始节点表单信息
|
||||
WfDeployForm startDeployForm = buildDeployForm(deployId, startEvent);
|
||||
if (ObjectUtil.isNotNull(startDeployForm)) {
|
||||
deployFormList.add(startDeployForm);
|
||||
}
|
||||
// 保存用户节点表单信息
|
||||
Collection<UserTask> userTasks = ModelUtils.getAllUserTaskEvent(bpmnModel);
|
||||
if (CollUtil.isNotEmpty(userTasks)) {
|
||||
for (UserTask userTask : userTasks) {
|
||||
WfDeployForm userTaskDeployForm = buildDeployForm(deployId, userTask);
|
||||
if (ObjectUtil.isNotNull(userTaskDeployForm)) {
|
||||
deployFormList.add(userTaskDeployForm);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 批量新增部署流程和表单关联信息
|
||||
return baseMapper.insertBatch(deployFormList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程挂着的表单
|
||||
*
|
||||
* @param deployId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public WfFormVo selectDeployFormByDeployId(String deployId) {
|
||||
QueryWrapper<WfForm> wrapper = Wrappers.query();
|
||||
wrapper.eq("t2.deploy_id", deployId);
|
||||
List<WfFormVo> list = formMapper.selectFormVoList(wrapper);
|
||||
if (ObjectUtil.isNotEmpty(list)) {
|
||||
if (list.size() != 1) {
|
||||
throw new ServiceException("表单信息查询错误");
|
||||
} else {
|
||||
return list.get(0);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建部署表单关联信息对象
|
||||
* @param deployId 部署ID
|
||||
* @param node 节点信息
|
||||
* @return 部署表单关联对象。若无表单信息(formKey),则返回null
|
||||
*/
|
||||
private WfDeployForm buildDeployForm(String deployId, FlowNode node) {
|
||||
String formKey = ModelUtils.getFormKey(node);
|
||||
if (StringUtils.isEmpty(formKey)) {
|
||||
return null;
|
||||
}
|
||||
Long formId = Convert.toLong(StringUtils.substringAfter(formKey, "key_"));
|
||||
WfForm wfForm = formMapper.selectById(formId);
|
||||
if (ObjectUtil.isNull(wfForm)) {
|
||||
throw new ServiceException("表单信息查询错误");
|
||||
}
|
||||
WfDeployForm deployForm = new WfDeployForm();
|
||||
deployForm.setDeployId(deployId);
|
||||
deployForm.setFormKey(formKey);
|
||||
deployForm.setNodeKey(node.getId());
|
||||
deployForm.setFormName(wfForm.getFormName());
|
||||
deployForm.setNodeName(node.getName());
|
||||
deployForm.setContent(wfForm.getContent());
|
||||
return deployForm;
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.flowable.core.domain.ProcessQuery;
|
||||
import com.klp.flowable.utils.ProcessUtils;
|
||||
import com.klp.workflow.domain.WfDeployForm;
|
||||
import com.klp.workflow.domain.vo.WfDeployVo;
|
||||
import com.klp.workflow.mapper.WfDeployFormMapper;
|
||||
import com.klp.workflow.service.IWfDeployService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.flowable.common.engine.impl.db.SuspensionState;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
import org.flowable.engine.repository.ProcessDefinitionQuery;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/30 9:04
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class WfDeployServiceImpl implements IWfDeployService {
|
||||
|
||||
private final RepositoryService repositoryService;
|
||||
private final WfDeployFormMapper deployFormMapper;
|
||||
|
||||
@Override
|
||||
public TableDataInfo<WfDeployVo> queryPageList(ProcessQuery processQuery, PageQuery pageQuery) {
|
||||
// 流程定义列表数据查询
|
||||
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
|
||||
.latestVersion()
|
||||
.orderByProcessDefinitionKey()
|
||||
.asc();
|
||||
// 构建搜索条件
|
||||
ProcessUtils.buildProcessSearch(processDefinitionQuery, processQuery);
|
||||
long pageTotal = processDefinitionQuery.count();
|
||||
if (pageTotal <= 0) {
|
||||
return TableDataInfo.build();
|
||||
}
|
||||
int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
|
||||
List<ProcessDefinition> definitionList = processDefinitionQuery.listPage(offset, pageQuery.getPageSize());
|
||||
|
||||
List<WfDeployVo> deployVoList = new ArrayList<>(definitionList.size());
|
||||
for (ProcessDefinition processDefinition : definitionList) {
|
||||
String deploymentId = processDefinition.getDeploymentId();
|
||||
Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
|
||||
WfDeployVo vo = new WfDeployVo();
|
||||
vo.setDefinitionId(processDefinition.getId());
|
||||
vo.setProcessKey(processDefinition.getKey());
|
||||
vo.setProcessName(processDefinition.getName());
|
||||
vo.setVersion(processDefinition.getVersion());
|
||||
vo.setCategory(processDefinition.getCategory());
|
||||
vo.setDeploymentId(processDefinition.getDeploymentId());
|
||||
vo.setSuspended(processDefinition.isSuspended());
|
||||
// 流程部署信息
|
||||
vo.setCategory(deployment.getCategory());
|
||||
vo.setDeploymentTime(deployment.getDeploymentTime());
|
||||
deployVoList.add(vo);
|
||||
}
|
||||
Page<WfDeployVo> page = new Page<>();
|
||||
page.setRecords(deployVoList);
|
||||
page.setTotal(pageTotal);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<WfDeployVo> queryPublishList(String processKey, PageQuery pageQuery) {
|
||||
// 创建查询条件
|
||||
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
|
||||
.processDefinitionKey(processKey)
|
||||
.orderByProcessDefinitionVersion()
|
||||
.desc();
|
||||
long pageTotal = processDefinitionQuery.count();
|
||||
if (pageTotal <= 0) {
|
||||
return TableDataInfo.build();
|
||||
}
|
||||
// 根据查询条件,查询所有版本
|
||||
int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
|
||||
List<ProcessDefinition> processDefinitionList = processDefinitionQuery
|
||||
.listPage(offset, pageQuery.getPageSize());
|
||||
List<WfDeployVo> deployVoList = processDefinitionList.stream().map(item -> {
|
||||
WfDeployVo vo = new WfDeployVo();
|
||||
vo.setDefinitionId(item.getId());
|
||||
vo.setProcessKey(item.getKey());
|
||||
vo.setProcessName(item.getName());
|
||||
vo.setVersion(item.getVersion());
|
||||
vo.setCategory(item.getCategory());
|
||||
vo.setDeploymentId(item.getDeploymentId());
|
||||
vo.setSuspended(item.isSuspended());
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
Page<WfDeployVo> page = new Page<>();
|
||||
page.setRecords(deployVoList);
|
||||
page.setTotal(pageTotal);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活或挂起流程
|
||||
*
|
||||
* @param state 状态
|
||||
* @param definitionId 流程定义ID
|
||||
*/
|
||||
@Override
|
||||
public void updateState(String definitionId, String state) {
|
||||
if (SuspensionState.ACTIVE.toString().equals(state)) {
|
||||
// 激活
|
||||
repositoryService.activateProcessDefinitionById(definitionId, true, null);
|
||||
} else if (SuspensionState.SUSPENDED.toString().equals(state)) {
|
||||
// 挂起
|
||||
repositoryService.suspendProcessDefinitionById(definitionId, true, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryBpmnXmlById(String definitionId) {
|
||||
InputStream inputStream = repositoryService.getProcessModel(definitionId);
|
||||
try {
|
||||
return IoUtil.readUtf8(inputStream);
|
||||
} catch (IORuntimeException exception) {
|
||||
throw new RuntimeException("加载xml文件异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteByIds(List<String> deployIds) {
|
||||
for (String deployId : deployIds) {
|
||||
repositoryService.deleteDeployment(deployId, true);
|
||||
deployFormMapper.delete(new LambdaQueryWrapper<WfDeployForm>().eq(WfDeployForm::getDeployId, deployId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.workflow.domain.WfForm;
|
||||
import com.klp.workflow.domain.bo.WfFormBo;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import com.klp.workflow.mapper.WfFormMapper;
|
||||
import com.klp.workflow.service.IWfFormService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程表单Service业务层处理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/7 22:07
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class WfFormServiceImpl implements IWfFormService {
|
||||
|
||||
private final WfFormMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询流程表单
|
||||
*
|
||||
* @param formId 流程表单ID
|
||||
* @return 流程表单
|
||||
*/
|
||||
@Override
|
||||
public WfFormVo queryById(Long formId) {
|
||||
return baseMapper.selectVoById(formId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程表单列表
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 流程表单
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<WfFormVo> queryPageList(WfFormBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<WfForm> lqw = buildQueryWrapper(bo);
|
||||
Page<WfFormVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流程表单列表
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 流程表单
|
||||
*/
|
||||
@Override
|
||||
public List<WfFormVo> queryList(WfFormBo bo) {
|
||||
LambdaQueryWrapper<WfForm> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程表单
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertForm(WfFormBo bo) {
|
||||
WfForm wfForm = new WfForm();
|
||||
wfForm.setFormName(bo.getFormName());
|
||||
wfForm.setContent(bo.getContent());
|
||||
wfForm.setRemark(bo.getRemark());
|
||||
return baseMapper.insert(wfForm);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改流程表单
|
||||
*
|
||||
* @param bo 流程表单
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateForm(WfFormBo bo) {
|
||||
return baseMapper.update(new WfForm(), new LambdaUpdateWrapper<WfForm>()
|
||||
.set(StrUtil.isNotBlank(bo.getFormName()), WfForm::getFormName, bo.getFormName())
|
||||
.set(StrUtil.isNotBlank(bo.getContent()), WfForm::getContent, bo.getContent())
|
||||
.set(StrUtil.isNotBlank(bo.getRemark()), WfForm::getRemark, bo.getRemark())
|
||||
.eq(WfForm::getFormId, bo.getFormId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除流程表单
|
||||
*
|
||||
* @param ids 需要删除的流程表单ID
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids) {
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<WfForm> buildQueryWrapper(WfFormBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<WfForm> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getFormName()), WfForm::getFormName, bo.getFormName());
|
||||
return lqw;
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.BetweenFormatter;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.klp.common.core.domain.entity.SysDept;
|
||||
import com.klp.common.core.domain.entity.SysRole;
|
||||
import com.klp.common.core.service.UserService;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.common.utils.JsonUtils;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.flowable.common.constant.TaskConstants;
|
||||
import com.klp.flowable.factory.FlowServiceFactory;
|
||||
import com.klp.system.service.ISysDeptService;
|
||||
import com.klp.system.service.ISysRoleService;
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import com.klp.workflow.domain.vo.WfTaskVo;
|
||||
import com.klp.workflow.service.IWfDeployFormService;
|
||||
import com.klp.workflow.service.IWfInstanceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.task.Comment;
|
||||
import org.flowable.identitylink.api.history.HistoricIdentityLink;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工作流流程实例管理
|
||||
*
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WfInstanceServiceImpl extends FlowServiceFactory implements IWfInstanceService {
|
||||
|
||||
private final IWfDeployFormService deployFormService;
|
||||
private final UserService userService;
|
||||
private final ISysRoleService roleService;
|
||||
private final ISysDeptService deptService;
|
||||
|
||||
/**
|
||||
* 结束流程实例
|
||||
*
|
||||
* @param vo
|
||||
*/
|
||||
@Override
|
||||
public void stopProcessInstance(WfTaskBo vo) {
|
||||
String taskId = vo.getTaskId();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活或挂起流程实例
|
||||
*
|
||||
* @param state 状态
|
||||
* @param instanceId 流程实例ID
|
||||
*/
|
||||
@Override
|
||||
public void updateState(Integer state, String instanceId) {
|
||||
|
||||
// 激活
|
||||
if (state == 1) {
|
||||
runtimeService.activateProcessInstanceById(instanceId);
|
||||
}
|
||||
// 挂起
|
||||
if (state == 2) {
|
||||
runtimeService.suspendProcessInstanceById(instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程实例ID
|
||||
*
|
||||
* @param instanceId 流程实例ID
|
||||
* @param deleteReason 删除原因
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(String instanceId, String deleteReason) {
|
||||
|
||||
// 查询历史数据
|
||||
HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(instanceId);
|
||||
if (historicProcessInstance.getEndTime() != null) {
|
||||
historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
|
||||
return;
|
||||
}
|
||||
// 删除流程实例
|
||||
runtimeService.deleteProcessInstance(instanceId, deleteReason);
|
||||
// 删除历史流程实例
|
||||
historyService.deleteHistoricProcessInstance(instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实例ID查询历史实例数据
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId) {
|
||||
HistoricProcessInstance historicProcessInstance =
|
||||
historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
if (Objects.isNull(historicProcessInstance)) {
|
||||
throw new FlowableObjectNotFoundException("流程实例不存在: " + processInstanceId);
|
||||
}
|
||||
return historicProcessInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 流程历史流转记录
|
||||
*
|
||||
* @param procInsId 流程实例Id
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> queryDetailProcess(String procInsId, String deployId) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (StringUtils.isNotBlank(procInsId)) {
|
||||
List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
|
||||
.processInstanceId(procInsId)
|
||||
.orderByHistoricTaskInstanceStartTime().desc()
|
||||
.list();
|
||||
List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);
|
||||
List<WfTaskVo> taskVoList = new ArrayList<>(taskInstanceList.size());
|
||||
taskInstanceList.forEach(taskInstance -> {
|
||||
WfTaskVo taskVo = new WfTaskVo();
|
||||
taskVo.setProcDefId(taskInstance.getProcessDefinitionId());
|
||||
taskVo.setTaskId(taskInstance.getId());
|
||||
taskVo.setTaskDefKey(taskInstance.getTaskDefinitionKey());
|
||||
taskVo.setTaskName(taskInstance.getName());
|
||||
taskVo.setCreateTime(taskInstance.getStartTime());
|
||||
taskVo.setFinishTime(taskInstance.getEndTime());
|
||||
if (StringUtils.isNotBlank(taskInstance.getAssignee())) {
|
||||
Long userId = Long.parseLong(taskInstance.getAssignee());
|
||||
String nickName = userService.selectNickNameById(userId);
|
||||
taskVo.setAssigneeId(userId);
|
||||
taskVo.setAssigneeName(nickName);
|
||||
}
|
||||
// 展示审批人员
|
||||
List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(taskInstance.getId());
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (HistoricIdentityLink identityLink : linksForTask) {
|
||||
if ("candidate".equals(identityLink.getType())) {
|
||||
if (StringUtils.isNotBlank(identityLink.getUserId())) {
|
||||
Long userId = Long.parseLong(identityLink.getUserId());
|
||||
String nickName = userService.selectNickNameById(userId);
|
||||
stringBuilder.append(nickName).append(",");
|
||||
}
|
||||
if (StringUtils.isNotBlank(identityLink.getGroupId())) {
|
||||
if (identityLink.getGroupId().startsWith(TaskConstants.ROLE_GROUP_PREFIX)) {
|
||||
Long roleId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.ROLE_GROUP_PREFIX));
|
||||
SysRole role = roleService.selectRoleById(roleId);
|
||||
stringBuilder.append(role.getRoleName()).append(",");
|
||||
} else if (identityLink.getGroupId().startsWith(TaskConstants.DEPT_GROUP_PREFIX)) {
|
||||
Long deptId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.DEPT_GROUP_PREFIX));
|
||||
SysDept dept = deptService.selectDeptById(deptId);
|
||||
stringBuilder.append(dept.getDeptName()).append(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(stringBuilder)) {
|
||||
taskVo.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
|
||||
}
|
||||
if (ObjectUtil.isNotNull(taskInstance.getDurationInMillis())) {
|
||||
taskVo.setDuration(DateUtil.formatBetween(taskInstance.getDurationInMillis(), BetweenFormatter.Level.SECOND));
|
||||
}
|
||||
// 获取意见评论内容
|
||||
if (CollUtil.isNotEmpty(commentList)) {
|
||||
List<Comment> comments = new ArrayList<>();
|
||||
// commentList.stream().filter(comment -> taskInstance.getId().equals(comment.getTaskId())).collect(Collectors.toList());
|
||||
for (Comment comment : commentList) {
|
||||
if (comment.getTaskId().equals(taskInstance.getId())) {
|
||||
comments.add(comment);
|
||||
// taskVo.setComment(WfCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build());
|
||||
}
|
||||
}
|
||||
taskVo.setCommentList(comments);
|
||||
}
|
||||
taskVoList.add(taskVo);
|
||||
});
|
||||
map.put("flowList", taskVoList);
|
||||
// // 查询当前任务是否完成
|
||||
// List<Task> taskList = taskService.createTaskQuery().processInstanceId(procInsId).list();
|
||||
// if (CollectionUtils.isNotEmpty(taskList)) {
|
||||
// map.put("finished", true);
|
||||
// } else {
|
||||
// map.put("finished", false);
|
||||
// }
|
||||
}
|
||||
// 第一次申请获取初始化表单
|
||||
if (StringUtils.isNotBlank(deployId)) {
|
||||
WfFormVo formVo = deployFormService.selectDeployFormByDeployId(deployId);
|
||||
if (Objects.isNull(formVo)) {
|
||||
throw new ServiceException("请先配置流程表单");
|
||||
}
|
||||
map.put("formData", JsonUtils.parseObject(formVo.getContent(), Map.class));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -1,359 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.common.utils.JsonUtils;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.flowable.common.constant.ProcessConstants;
|
||||
import com.klp.flowable.common.enums.FormType;
|
||||
import com.klp.flowable.factory.FlowServiceFactory;
|
||||
import com.klp.flowable.utils.ModelUtils;
|
||||
import com.klp.workflow.domain.bo.WfModelBo;
|
||||
import com.klp.workflow.domain.dto.WfMetaInfoDto;
|
||||
import com.klp.workflow.domain.vo.WfFormVo;
|
||||
import com.klp.workflow.domain.vo.WfModelVo;
|
||||
import com.klp.workflow.service.IWfDeployFormService;
|
||||
import com.klp.workflow.service.IWfFormService;
|
||||
import com.klp.workflow.service.IWfModelService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.StartEvent;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.flowable.engine.repository.Model;
|
||||
import org.flowable.engine.repository.ModelQuery;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/6/21 9:11
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WfModelServiceImpl extends FlowServiceFactory implements IWfModelService {
|
||||
|
||||
private final IWfFormService formService;
|
||||
private final IWfDeployFormService deployFormService;
|
||||
|
||||
@Override
|
||||
public TableDataInfo<WfModelVo> list(WfModelBo modelBo, PageQuery pageQuery) {
|
||||
ModelQuery modelQuery = repositoryService.createModelQuery().latestVersion().orderByCreateTime().desc();
|
||||
// 构建查询条件
|
||||
if (StringUtils.isNotBlank(modelBo.getModelKey())) {
|
||||
modelQuery.modelKey(modelBo.getModelKey());
|
||||
}
|
||||
if (StringUtils.isNotBlank(modelBo.getModelName())) {
|
||||
modelQuery.modelNameLike("%" + modelBo.getModelName() + "%");
|
||||
}
|
||||
if (StringUtils.isNotBlank(modelBo.getCategory())) {
|
||||
modelQuery.modelCategory(modelBo.getCategory());
|
||||
}
|
||||
// 执行查询
|
||||
long pageTotal = modelQuery.count();
|
||||
if (pageTotal <= 0) {
|
||||
return TableDataInfo.build();
|
||||
}
|
||||
int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
|
||||
List<Model> modelList = modelQuery.listPage(offset, pageQuery.getPageSize());
|
||||
List<WfModelVo> modelVoList = new ArrayList<>(modelList.size());
|
||||
modelList.forEach(model -> {
|
||||
WfModelVo modelVo = new WfModelVo();
|
||||
modelVo.setModelId(model.getId());
|
||||
modelVo.setModelName(model.getName());
|
||||
modelVo.setModelKey(model.getKey());
|
||||
modelVo.setCategory(model.getCategory());
|
||||
modelVo.setCreateTime(model.getCreateTime());
|
||||
modelVo.setVersion(model.getVersion());
|
||||
WfMetaInfoDto metaInfo = JsonUtils.parseObject(model.getMetaInfo(), WfMetaInfoDto.class);
|
||||
if (metaInfo != null) {
|
||||
modelVo.setDescription(metaInfo.getDescription());
|
||||
modelVo.setFormType(metaInfo.getFormType());
|
||||
modelVo.setFormId(metaInfo.getFormId());
|
||||
}
|
||||
modelVoList.add(modelVo);
|
||||
});
|
||||
Page<WfModelVo> page = new Page<>();
|
||||
page.setRecords(modelVoList);
|
||||
page.setTotal(pageTotal);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WfModelVo> list(WfModelBo modelBo) {
|
||||
ModelQuery modelQuery = repositoryService.createModelQuery().latestVersion().orderByCreateTime().desc();
|
||||
// 构建查询条件
|
||||
if (StringUtils.isNotBlank(modelBo.getModelKey())) {
|
||||
modelQuery.modelKey(modelBo.getModelKey());
|
||||
}
|
||||
if (StringUtils.isNotBlank(modelBo.getModelName())) {
|
||||
modelQuery.modelNameLike("%" + modelBo.getModelName() + "%");
|
||||
}
|
||||
if (StringUtils.isNotBlank(modelBo.getCategory())) {
|
||||
modelQuery.modelCategory(modelBo.getCategory());
|
||||
}
|
||||
List<Model> modelList = modelQuery.list();
|
||||
List<WfModelVo> modelVoList = new ArrayList<>(modelList.size());
|
||||
modelList.forEach(model -> {
|
||||
WfModelVo modelVo = new WfModelVo();
|
||||
modelVo.setModelId(model.getId());
|
||||
modelVo.setModelName(model.getName());
|
||||
modelVo.setModelKey(model.getKey());
|
||||
modelVo.setCategory(model.getCategory());
|
||||
modelVo.setCreateTime(model.getCreateTime());
|
||||
modelVo.setVersion(model.getVersion());
|
||||
WfMetaInfoDto metaInfo = JsonUtils.parseObject(model.getMetaInfo(), WfMetaInfoDto.class);
|
||||
if (metaInfo != null) {
|
||||
modelVo.setDescription(metaInfo.getDescription());
|
||||
modelVo.setFormType(metaInfo.getFormType());
|
||||
modelVo.setFormId(metaInfo.getFormId());
|
||||
}
|
||||
modelVoList.add(modelVo);
|
||||
});
|
||||
return modelVoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<WfModelVo> historyList(WfModelBo modelBo, PageQuery pageQuery) {
|
||||
ModelQuery modelQuery = repositoryService.createModelQuery()
|
||||
.modelKey(modelBo.getModelKey())
|
||||
.orderByModelVersion()
|
||||
.desc();
|
||||
// 执行查询(不显示最新版,-1)
|
||||
long pageTotal = modelQuery.count() - 1;
|
||||
if (pageTotal <= 0) {
|
||||
return TableDataInfo.build();
|
||||
}
|
||||
// offset+1,去掉最新版
|
||||
int offset = 1 + pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
|
||||
List<Model> modelList = modelQuery.listPage(offset, pageQuery.getPageSize());
|
||||
List<WfModelVo> modelVoList = new ArrayList<>(modelList.size());
|
||||
modelList.forEach(model -> {
|
||||
WfModelVo modelVo = new WfModelVo();
|
||||
modelVo.setModelId(model.getId());
|
||||
modelVo.setModelName(model.getName());
|
||||
modelVo.setModelKey(model.getKey());
|
||||
modelVo.setCategory(model.getCategory());
|
||||
modelVo.setCreateTime(model.getCreateTime());
|
||||
modelVo.setVersion(model.getVersion());
|
||||
WfMetaInfoDto metaInfo = JsonUtils.parseObject(model.getMetaInfo(), WfMetaInfoDto.class);
|
||||
if (metaInfo != null) {
|
||||
modelVo.setDescription(metaInfo.getDescription());
|
||||
modelVo.setFormType(metaInfo.getFormType());
|
||||
modelVo.setFormId(metaInfo.getFormId());
|
||||
}
|
||||
modelVoList.add(modelVo);
|
||||
});
|
||||
Page<WfModelVo> page = new Page<>();
|
||||
page.setRecords(modelVoList);
|
||||
page.setTotal(pageTotal);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WfModelVo getModel(String modelId) {
|
||||
// 获取流程模型
|
||||
Model model = repositoryService.getModel(modelId);
|
||||
if (ObjectUtil.isNull(model)) {
|
||||
throw new RuntimeException("流程模型不存在!");
|
||||
}
|
||||
// 获取流程图
|
||||
String bpmnXml = queryBpmnXmlById(modelId);
|
||||
WfModelVo modelVo = new WfModelVo();
|
||||
modelVo.setModelId(model.getId());
|
||||
modelVo.setModelName(model.getName());
|
||||
modelVo.setModelKey(model.getKey());
|
||||
modelVo.setCategory(model.getCategory());
|
||||
modelVo.setCreateTime(model.getCreateTime());
|
||||
modelVo.setVersion(model.getVersion());
|
||||
modelVo.setBpmnXml(bpmnXml);
|
||||
WfMetaInfoDto metaInfo = JsonUtils.parseObject(model.getMetaInfo(), WfMetaInfoDto.class);
|
||||
if (metaInfo != null) {
|
||||
modelVo.setDescription(metaInfo.getDescription());
|
||||
modelVo.setFormType(metaInfo.getFormType());
|
||||
modelVo.setFormId(metaInfo.getFormId());
|
||||
if (FormType.PROCESS.getType().equals(metaInfo.getFormType())) {
|
||||
WfFormVo wfFormVo = formService.queryById(metaInfo.getFormId());
|
||||
modelVo.setContent(wfFormVo.getContent());
|
||||
}
|
||||
}
|
||||
return modelVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryBpmnXmlById(String modelId) {
|
||||
byte[] bpmnBytes = repositoryService.getModelEditorSource(modelId);
|
||||
return StrUtil.utf8Str(bpmnBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertModel(WfModelBo modelBo) {
|
||||
Model model = repositoryService.newModel();
|
||||
model.setName(modelBo.getModelName());
|
||||
model.setKey(modelBo.getModelKey());
|
||||
model.setCategory(modelBo.getCategory());
|
||||
String metaInfo = buildMetaInfo(new WfMetaInfoDto(), modelBo.getDescription());
|
||||
model.setMetaInfo(metaInfo);
|
||||
// 保存流程模型
|
||||
repositoryService.saveModel(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateModel(WfModelBo modelBo) {
|
||||
// 根据模型Key查询模型信息
|
||||
Model model = repositoryService.getModel(modelBo.getModelId());
|
||||
if (ObjectUtil.isNull(model)) {
|
||||
throw new RuntimeException("流程模型不存在!");
|
||||
}
|
||||
model.setCategory(modelBo.getCategory());
|
||||
WfMetaInfoDto metaInfoDto = JsonUtils.parseObject(model.getMetaInfo(), WfMetaInfoDto.class);
|
||||
String metaInfo = buildMetaInfo(metaInfoDto, modelBo.getDescription());
|
||||
model.setMetaInfo(metaInfo);
|
||||
// 保存流程模型
|
||||
repositoryService.saveModel(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveModel(WfModelBo modelBo) {
|
||||
// 查询模型信息
|
||||
Model model = repositoryService.getModel(modelBo.getModelId());
|
||||
if (ObjectUtil.isNull(model)) {
|
||||
throw new RuntimeException("流程模型不存在!");
|
||||
}
|
||||
BpmnModel bpmnModel = ModelUtils.getBpmnModel(modelBo.getBpmnXml());
|
||||
if (ObjectUtil.isEmpty(bpmnModel)) {
|
||||
throw new RuntimeException("获取模型设计失败!");
|
||||
}
|
||||
String processName = bpmnModel.getMainProcess().getName();
|
||||
// 获取开始节点
|
||||
StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
|
||||
if (ObjectUtil.isNull(startEvent)) {
|
||||
throw new RuntimeException("开始节点不存在,请检查流程设计是否有误!");
|
||||
}
|
||||
// 获取开始节点配置的表单Key
|
||||
if (StrUtil.isBlank(startEvent.getFormKey())) {
|
||||
throw new RuntimeException("请配置流程表单");
|
||||
}
|
||||
Model newModel;
|
||||
if (Boolean.TRUE.equals(modelBo.getNewVersion())) {
|
||||
newModel = repositoryService.newModel();
|
||||
newModel.setName(processName);
|
||||
newModel.setKey(model.getKey());
|
||||
newModel.setCategory(model.getCategory());
|
||||
newModel.setMetaInfo(model.getMetaInfo());
|
||||
newModel.setVersion(model.getVersion() + 1);
|
||||
} else {
|
||||
newModel = model;
|
||||
// 设置流程名称
|
||||
newModel.setName(processName);
|
||||
}
|
||||
// 保存流程模型
|
||||
repositoryService.saveModel(newModel);
|
||||
// 保存 BPMN XML
|
||||
byte[] bpmnXmlBytes = StringUtils.getBytes(modelBo.getBpmnXml(), StandardCharsets.UTF_8);
|
||||
repositoryService.addModelEditorSource(newModel.getId(), bpmnXmlBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void latestModel(String modelId) {
|
||||
// 获取流程模型
|
||||
Model model = repositoryService.getModel(modelId);
|
||||
if (ObjectUtil.isNull(model)) {
|
||||
throw new RuntimeException("流程模型不存在!");
|
||||
}
|
||||
Integer latestVersion = repositoryService.createModelQuery()
|
||||
.modelKey(model.getKey())
|
||||
.latestVersion()
|
||||
.singleResult()
|
||||
.getVersion();
|
||||
if (model.getVersion().equals(latestVersion)) {
|
||||
throw new RuntimeException("当前版本已是最新版!");
|
||||
}
|
||||
// 获取 BPMN XML
|
||||
byte[] bpmnBytes = repositoryService.getModelEditorSource(modelId);
|
||||
Model newModel = repositoryService.newModel();
|
||||
newModel.setName(model.getName());
|
||||
newModel.setKey(model.getKey());
|
||||
newModel.setCategory(model.getCategory());
|
||||
newModel.setMetaInfo(model.getMetaInfo());
|
||||
newModel.setVersion(latestVersion + 1);
|
||||
// 保存流程模型
|
||||
repositoryService.saveModel(newModel);
|
||||
// 保存 BPMN XML
|
||||
repositoryService.addModelEditorSource(newModel.getId(), bpmnBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteByIds(Collection<String> ids) {
|
||||
ids.forEach(id -> {
|
||||
Model model = repositoryService.getModel(id);
|
||||
if (ObjectUtil.isNull(model)) {
|
||||
throw new RuntimeException("流程模型不存在!");
|
||||
}
|
||||
repositoryService.deleteModel(id);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deployModel(String modelId) {
|
||||
// 获取流程模型
|
||||
Model model = repositoryService.getModel(modelId);
|
||||
if (ObjectUtil.isNull(model)) {
|
||||
throw new RuntimeException("流程模型不存在!");
|
||||
}
|
||||
// 获取流程图
|
||||
byte[] bpmnBytes = repositoryService.getModelEditorSource(modelId);
|
||||
if (ArrayUtil.isEmpty(bpmnBytes)) {
|
||||
throw new RuntimeException("请先设计流程图!");
|
||||
}
|
||||
String bpmnXml = StringUtils.toEncodedString(bpmnBytes, StandardCharsets.UTF_8);
|
||||
BpmnModel bpmnModel = ModelUtils.getBpmnModel(bpmnXml);
|
||||
String processName = model.getName() + ProcessConstants.SUFFIX;
|
||||
// 部署流程
|
||||
Deployment deployment = repositoryService.createDeployment()
|
||||
.name(model.getName())
|
||||
.key(model.getKey())
|
||||
.category(model.getCategory())
|
||||
.addBytes(processName, bpmnBytes)
|
||||
.deploy();
|
||||
ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
|
||||
.deploymentId(deployment.getId())
|
||||
.singleResult();
|
||||
// 修改流程定义的分类,便于搜索流程
|
||||
repositoryService.setProcessDefinitionCategory(procDef.getId(), model.getCategory());
|
||||
// 保存部署表单
|
||||
return deployFormService.saveInternalDeployForm(deployment.getId(), bpmnModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建模型扩展信息
|
||||
* @return
|
||||
*/
|
||||
private String buildMetaInfo(WfMetaInfoDto metaInfo, String description) {
|
||||
// 只有非空,才进行设置,避免更新时的覆盖
|
||||
if (StringUtils.isNotEmpty(description)) {
|
||||
metaInfo.setDescription(description);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(metaInfo.getCreateUser())) {
|
||||
metaInfo.setCreateUser(LoginHelper.getUsername());
|
||||
}
|
||||
return JsonUtils.toJsonString(metaInfo);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,625 +0,0 @@
|
||||
package com.klp.workflow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.klp.common.core.service.UserService;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.flowable.common.constant.ProcessConstants;
|
||||
import com.klp.flowable.common.constant.TaskConstants;
|
||||
import com.klp.flowable.common.enums.FlowComment;
|
||||
import com.klp.flowable.common.enums.ProcessStatus;
|
||||
import com.klp.flowable.factory.FlowServiceFactory;
|
||||
import com.klp.flowable.flow.CustomProcessDiagramGenerator;
|
||||
import com.klp.flowable.flow.FlowableUtils;
|
||||
import com.klp.flowable.utils.ModelUtils;
|
||||
import com.klp.flowable.utils.TaskUtils;
|
||||
import com.klp.workflow.domain.bo.WfTaskBo;
|
||||
import com.klp.workflow.service.IWfCopyService;
|
||||
import com.klp.workflow.service.IWfTaskService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.flowable.bpmn.constants.BpmnXMLConstants;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.common.engine.api.FlowableException;
|
||||
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
|
||||
import org.flowable.common.engine.impl.identity.Authentication;
|
||||
import org.flowable.engine.ProcessEngineConfiguration;
|
||||
import org.flowable.engine.history.HistoricActivityInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
import org.flowable.engine.runtime.Execution;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.image.ProcessDiagramGenerator;
|
||||
import org.flowable.task.api.DelegationState;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author KonBAI
|
||||
* @createTime 2022/3/10 00:12
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskService {
|
||||
|
||||
private final UserService sysUserService;
|
||||
|
||||
private final IWfCopyService copyService;
|
||||
|
||||
/**
|
||||
* 完成任务
|
||||
*
|
||||
* @param taskBo 请求实体参数
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void complete(WfTaskBo taskBo) {
|
||||
Task task = taskService.createTaskQuery().taskId(taskBo.getTaskId()).singleResult();
|
||||
if (Objects.isNull(task)) {
|
||||
throw new ServiceException("任务不存在");
|
||||
}
|
||||
// 获取 bpmn 模型
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
if (DelegationState.PENDING.equals(task.getDelegationState())) {
|
||||
taskService.addComment(taskBo.getTaskId(), taskBo.getProcInsId(), FlowComment.DELEGATE.getType(), taskBo.getComment());
|
||||
taskService.resolveTask(taskBo.getTaskId());
|
||||
} else {
|
||||
taskService.addComment(taskBo.getTaskId(), taskBo.getProcInsId(), FlowComment.NORMAL.getType(), taskBo.getComment());
|
||||
taskService.setAssignee(taskBo.getTaskId(), TaskUtils.getUserId());
|
||||
if (ObjectUtil.isNotEmpty(taskBo.getVariables())) {
|
||||
// 获取模型信息
|
||||
String localScopeValue = ModelUtils.getUserTaskAttributeValue(bpmnModel, task.getTaskDefinitionKey(), ProcessConstants.PROCESS_FORM_LOCAL_SCOPE);
|
||||
boolean localScope = Convert.toBool(localScopeValue, false);
|
||||
taskService.complete(taskBo.getTaskId(), taskBo.getVariables(), localScope);
|
||||
} else {
|
||||
taskService.complete(taskBo.getTaskId());
|
||||
}
|
||||
}
|
||||
// 设置任务节点名称
|
||||
taskBo.setTaskName(task.getName());
|
||||
// 处理下一级审批人
|
||||
if (StringUtils.isNotBlank(taskBo.getNextUserIds())) {
|
||||
this.assignNextUsers(bpmnModel, taskBo.getProcInsId(), taskBo.getNextUserIds());
|
||||
}
|
||||
// 处理抄送用户
|
||||
if (!copyService.makeCopy(taskBo)) {
|
||||
throw new RuntimeException("抄送任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝任务
|
||||
*
|
||||
* @param taskBo
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void taskReject(WfTaskBo taskBo) {
|
||||
// 当前任务 task
|
||||
Task task = taskService.createTaskQuery().taskId(taskBo.getTaskId()).singleResult();
|
||||
if (ObjectUtil.isNull(task)) {
|
||||
throw new RuntimeException("获取任务信息异常!");
|
||||
}
|
||||
if (task.isSuspended()) {
|
||||
throw new RuntimeException("任务处于挂起状态");
|
||||
}
|
||||
// 获取流程实例
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(taskBo.getProcInsId())
|
||||
.singleResult();
|
||||
if (processInstance == null) {
|
||||
throw new RuntimeException("流程实例不存在,请确认!");
|
||||
}
|
||||
// 获取流程定义信息
|
||||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
|
||||
.processDefinitionId(task.getProcessDefinitionId())
|
||||
.singleResult();
|
||||
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
// 添加审批意见
|
||||
taskService.addComment(taskBo.getTaskId(), taskBo.getProcInsId(), FlowComment.REJECT.getType(), taskBo.getComment());
|
||||
// 设置流程状态为已终结
|
||||
runtimeService.setVariable(processInstance.getId(), ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.TERMINATED.getStatus());
|
||||
// 获取所有节点信息
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
|
||||
EndEvent endEvent = ModelUtils.getEndEvent(bpmnModel);
|
||||
// 终止流程
|
||||
List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
|
||||
List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveExecutionsToSingleActivityId(executionIds, endEvent.getId())
|
||||
.changeState();
|
||||
// 处理抄送用户
|
||||
if (!copyService.makeCopy(taskBo)) {
|
||||
throw new RuntimeException("抄送任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退回任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void taskReturn(WfTaskBo bo) {
|
||||
// 当前任务 task
|
||||
Task task = taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult();
|
||||
if (ObjectUtil.isNull(task)) {
|
||||
throw new RuntimeException("获取任务信息异常!");
|
||||
}
|
||||
if (task.isSuspended()) {
|
||||
throw new RuntimeException("任务处于挂起状态");
|
||||
}
|
||||
// 获取流程定义信息
|
||||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
|
||||
// 获取流程模型信息
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
|
||||
// 获取当前任务节点元素
|
||||
FlowElement source = ModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
|
||||
// 获取跳转的节点元素
|
||||
FlowElement target = ModelUtils.getFlowElementById(bpmnModel, bo.getTargetKey());
|
||||
// 从当前节点向前扫描,判断当前节点与目标节点是否属于串行,若目标节点是在并行网关上或非同一路线上,不可跳转
|
||||
boolean isSequential = ModelUtils.isSequentialReachable(source, target, new HashSet<>());
|
||||
if (!isSequential) {
|
||||
throw new RuntimeException("当前节点相对于目标节点,不属于串行关系,无法回退");
|
||||
}
|
||||
|
||||
// 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务
|
||||
List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
|
||||
List<String> runTaskKeyList = new ArrayList<>();
|
||||
runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
|
||||
// 需退回任务列表
|
||||
List<String> currentIds = new ArrayList<>();
|
||||
// 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务
|
||||
List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null);
|
||||
currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
|
||||
|
||||
// 循环获取那些需要被撤回的节点的ID,用来设置驳回原因
|
||||
List<String> currentTaskIds = new ArrayList<>();
|
||||
currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
|
||||
if (currentId.equals(runTask.getTaskDefinitionKey())) {
|
||||
currentTaskIds.add(runTask.getId());
|
||||
}
|
||||
}));
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
// 设置回退意见
|
||||
for (String currentTaskId : currentTaskIds) {
|
||||
taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), bo.getComment());
|
||||
}
|
||||
|
||||
try {
|
||||
// 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1)
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveActivityIdsToSingleActivityId(currentIds, bo.getTargetKey()).changeState();
|
||||
} catch (FlowableObjectNotFoundException e) {
|
||||
throw new RuntimeException("未找到流程实例,流程可能已发生变化");
|
||||
} catch (FlowableException e) {
|
||||
throw new RuntimeException("无法取消或开始活动");
|
||||
}
|
||||
// 设置任务节点名称
|
||||
bo.setTaskName(task.getName());
|
||||
// 处理抄送用户
|
||||
if (!copyService.makeCopy(bo)) {
|
||||
throw new RuntimeException("抄送任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有可回退的节点
|
||||
*
|
||||
* @param bo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<FlowElement> findReturnTaskList(WfTaskBo bo) {
|
||||
// 当前任务 task
|
||||
Task task = taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult();
|
||||
// 获取流程定义信息
|
||||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
|
||||
// 获取流程模型信息
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
|
||||
// 查询历史节点实例
|
||||
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.activityType(BpmnXMLConstants.ELEMENT_TASK_USER)
|
||||
.finished()
|
||||
.orderByHistoricActivityInstanceEndTime().asc()
|
||||
.list();
|
||||
List<String> activityIdList = activityInstanceList.stream()
|
||||
.map(HistoricActivityInstance::getActivityId)
|
||||
.filter(activityId -> !StringUtils.equals(activityId, task.getTaskDefinitionKey()))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
// 获取当前任务节点元素
|
||||
FlowElement source = ModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
|
||||
List<FlowElement> elementList = new ArrayList<>();
|
||||
for (String activityId : activityIdList) {
|
||||
FlowElement target = ModelUtils.getFlowElementById(bpmnModel, activityId);
|
||||
boolean isSequential = ModelUtils.isSequentialReachable(source, target, new HashSet<>());
|
||||
if (isSequential) {
|
||||
elementList.add(target);
|
||||
}
|
||||
}
|
||||
return elementList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
@Override
|
||||
public void deleteTask(WfTaskBo bo) {
|
||||
// todo 待确认删除任务是物理删除任务 还是逻辑删除,让这个任务直接通过?
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
taskService.deleteTask(bo.getTaskId(), bo.getComment());
|
||||
}
|
||||
|
||||
/**
|
||||
* 认领/签收任务
|
||||
*
|
||||
* @param taskBo 请求实体参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void claim(WfTaskBo taskBo) {
|
||||
Task task = taskService.createTaskQuery().taskId(taskBo.getTaskId()).singleResult();
|
||||
if (Objects.isNull(task)) {
|
||||
throw new ServiceException("任务不存在");
|
||||
}
|
||||
taskService.claim(taskBo.getTaskId(), TaskUtils.getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消认领/签收任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void unClaim(WfTaskBo bo) {
|
||||
taskService.unclaim(bo.getTaskId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 委派任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delegateTask(WfTaskBo bo) {
|
||||
// 当前任务 task
|
||||
Task task = taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult();
|
||||
if (ObjectUtil.isEmpty(task)) {
|
||||
throw new ServiceException("获取任务失败!");
|
||||
}
|
||||
StringBuilder commentBuilder = new StringBuilder(LoginHelper.getNickName())
|
||||
.append("->");
|
||||
String nickName = sysUserService.selectNickNameById(Long.parseLong(bo.getUserId()));
|
||||
if (StringUtils.isNotBlank(nickName)) {
|
||||
commentBuilder.append(nickName);
|
||||
} else {
|
||||
commentBuilder.append(bo.getUserId());
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getComment())) {
|
||||
commentBuilder.append(": ").append(bo.getComment());
|
||||
}
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
// 添加审批意见
|
||||
taskService.addComment(bo.getTaskId(), task.getProcessInstanceId(), FlowComment.DELEGATE.getType(), commentBuilder.toString());
|
||||
// 设置办理人为当前登录人
|
||||
taskService.setOwner(bo.getTaskId(), TaskUtils.getUserId());
|
||||
// 执行委派
|
||||
taskService.delegateTask(bo.getTaskId(), bo.getUserId());
|
||||
// 设置任务节点名称
|
||||
bo.setTaskName(task.getName());
|
||||
// 处理抄送用户
|
||||
if (!copyService.makeCopy(bo)) {
|
||||
throw new RuntimeException("抄送任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转办任务
|
||||
*
|
||||
* @param bo 请求实体参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void transferTask(WfTaskBo bo) {
|
||||
// 当前任务 task
|
||||
Task task = taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult();
|
||||
if (ObjectUtil.isEmpty(task)) {
|
||||
throw new ServiceException("获取任务失败!");
|
||||
}
|
||||
StringBuilder commentBuilder = new StringBuilder(LoginHelper.getNickName())
|
||||
.append("->");
|
||||
String nickName = sysUserService.selectNickNameById(Long.parseLong(bo.getUserId()));
|
||||
if (StringUtils.isNotBlank(nickName)) {
|
||||
commentBuilder.append(nickName);
|
||||
} else {
|
||||
commentBuilder.append(bo.getUserId());
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getComment())) {
|
||||
commentBuilder.append(": ").append(bo.getComment());
|
||||
}
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
// 添加审批意见
|
||||
taskService.addComment(bo.getTaskId(), task.getProcessInstanceId(), FlowComment.TRANSFER.getType(), commentBuilder.toString());
|
||||
// 设置拥有者为当前登录人
|
||||
taskService.setOwner(bo.getTaskId(), TaskUtils.getUserId());
|
||||
// 转办任务
|
||||
taskService.setAssignee(bo.getTaskId(), bo.getUserId());
|
||||
// 设置任务节点名称
|
||||
bo.setTaskName(task.getName());
|
||||
// 处理抄送用户
|
||||
if (!copyService.makeCopy(bo)) {
|
||||
throw new RuntimeException("抄送任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消申请
|
||||
*
|
||||
* @param bo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public void stopProcess(WfTaskBo bo) {
|
||||
List<Task> taskList = taskService.createTaskQuery().processInstanceId(bo.getProcInsId()).list();
|
||||
if (CollectionUtils.isEmpty(taskList)) {
|
||||
throw new RuntimeException("流程未启动或已执行完成,取消申请失败");
|
||||
}
|
||||
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(bo.getProcInsId()).singleResult();
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
|
||||
if (Objects.nonNull(bpmnModel)) {
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
|
||||
if (CollectionUtils.isNotEmpty(endNodes)) {
|
||||
Authentication.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
runtimeService.setVariable(processInstance.getId(), ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.CANCELED.getStatus());
|
||||
for (Task task : taskList) {
|
||||
taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(), "取消流程");
|
||||
}
|
||||
// 获取当前流程最后一个节点
|
||||
String endId = endNodes.get(0).getId();
|
||||
List<Execution> executions = runtimeService.createExecutionQuery()
|
||||
.parentId(processInstance.getProcessInstanceId()).list();
|
||||
List<String> executionIds = new ArrayList<>();
|
||||
executions.forEach(execution -> executionIds.add(execution.getId()));
|
||||
// 变更流程为已结束状态
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.moveExecutionsToSingleActivityId(executionIds, endId).changeState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回流程
|
||||
*
|
||||
* @param taskBo 请求实体参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void revokeProcess(WfTaskBo taskBo) {
|
||||
String procInsId = taskBo.getProcInsId();
|
||||
String taskId = taskBo.getTaskId();
|
||||
// 校验流程是否结束
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(procInsId)
|
||||
.active()
|
||||
.singleResult();
|
||||
if(ObjectUtil.isNull(processInstance)) {
|
||||
throw new RuntimeException("流程已结束或已挂起,无法执行撤回操作");
|
||||
}
|
||||
// 获取待撤回任务实例
|
||||
HistoricTaskInstance currTaskIns = historyService.createHistoricTaskInstanceQuery()
|
||||
.taskId(taskId)
|
||||
.taskAssignee(TaskUtils.getUserId())
|
||||
.singleResult();
|
||||
if (ObjectUtil.isNull(currTaskIns)) {
|
||||
throw new RuntimeException("当前任务不存在,无法执行撤回操作");
|
||||
}
|
||||
// 获取 bpmn 模型
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(currTaskIns.getProcessDefinitionId());
|
||||
UserTask currUserTask = ModelUtils.getUserTaskByKey(bpmnModel, currTaskIns.getTaskDefinitionKey());
|
||||
// 查找下一级用户任务列表
|
||||
List<UserTask> nextUserTaskList = ModelUtils.findNextUserTasks(currUserTask);
|
||||
List<String> nextUserTaskKeys = nextUserTaskList.stream().map(UserTask::getId).collect(Collectors.toList());
|
||||
|
||||
// 获取当前节点之后已完成的流程历史节点
|
||||
List<HistoricTaskInstance> finishedTaskInsList = historyService.createHistoricTaskInstanceQuery()
|
||||
.processInstanceId(procInsId)
|
||||
.taskCreatedAfter(currTaskIns.getEndTime())
|
||||
.finished()
|
||||
.list();
|
||||
for (HistoricTaskInstance finishedTaskInstance : finishedTaskInsList) {
|
||||
// 检查已完成流程历史节点是否存在下一级中
|
||||
if (CollUtil.contains(nextUserTaskKeys, finishedTaskInstance.getTaskDefinitionKey())) {
|
||||
throw new RuntimeException("下一流程已处理,无法执行撤回操作");
|
||||
}
|
||||
}
|
||||
// 获取所有激活的任务节点,找到需要撤回的任务
|
||||
List<Task> activateTaskList = taskService.createTaskQuery().processInstanceId(procInsId).list();
|
||||
List<String> revokeExecutionIds = new ArrayList<>();
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
for (Task task : activateTaskList) {
|
||||
// 检查激活的任务节点是否存在下一级中,如果存在,则加入到需要撤回的节点
|
||||
if (CollUtil.contains(nextUserTaskKeys, task.getTaskDefinitionKey())) {
|
||||
// 添加撤回审批信息
|
||||
taskService.setAssignee(task.getId(), TaskUtils.getUserId());
|
||||
taskService.addComment(task.getId(), task.getProcessInstanceId(), FlowComment.REVOKE.getType(), LoginHelper.getNickName() + "撤回流程审批");
|
||||
revokeExecutionIds.add(task.getExecutionId());
|
||||
}
|
||||
}
|
||||
try {
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(procInsId)
|
||||
.moveExecutionsToSingleActivityId(revokeExecutionIds, currTaskIns.getTaskDefinitionKey()).changeState();
|
||||
} catch (FlowableObjectNotFoundException e) {
|
||||
throw new RuntimeException("未找到流程实例,流程可能已发生变化");
|
||||
} catch (FlowableException e) {
|
||||
throw new RuntimeException("执行撤回操作失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程过程图
|
||||
*
|
||||
* @param processId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public InputStream diagram(String processId) {
|
||||
String processDefinitionId;
|
||||
// 获取当前的流程实例
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
|
||||
// 如果流程已经结束,则得到结束节点
|
||||
if (Objects.isNull(processInstance)) {
|
||||
HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
|
||||
|
||||
processDefinitionId = pi.getProcessDefinitionId();
|
||||
} else {// 如果流程没有结束,则取当前活动节点
|
||||
// 根据流程实例ID获得当前处于活动状态的ActivityId合集
|
||||
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
|
||||
processDefinitionId = pi.getProcessDefinitionId();
|
||||
}
|
||||
|
||||
// 获得活动的节点
|
||||
List<HistoricActivityInstance> highLightedFlowList = historyService.createHistoricActivityInstanceQuery()
|
||||
.processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
|
||||
|
||||
List<String> highLightedFlows = new ArrayList<>();
|
||||
List<String> highLightedNodes = new ArrayList<>();
|
||||
//高亮线
|
||||
for (HistoricActivityInstance tempActivity : highLightedFlowList) {
|
||||
if ("sequenceFlow".equals(tempActivity.getActivityType())) {
|
||||
//高亮线
|
||||
highLightedFlows.add(tempActivity.getActivityId());
|
||||
} else {
|
||||
//高亮节点
|
||||
highLightedNodes.add(tempActivity.getActivityId());
|
||||
}
|
||||
}
|
||||
|
||||
//获取流程图
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
||||
ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
|
||||
//获取自定义图片生成器
|
||||
ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
|
||||
return diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(),
|
||||
configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程变量
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
* @return 流程变量
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getProcessVariables(String taskId) {
|
||||
HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
|
||||
.includeProcessVariables()
|
||||
.finished()
|
||||
.taskId(taskId)
|
||||
.singleResult();
|
||||
if (Objects.nonNull(historicTaskInstance)) {
|
||||
return historicTaskInstance.getProcessVariables();
|
||||
}
|
||||
return taskService.getVariables(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动第一个任务
|
||||
* @param processInstance 流程实例
|
||||
* @param variables 流程参数
|
||||
*/
|
||||
@Override
|
||||
public void startFirstTask(ProcessInstance processInstance, Map<String, Object> variables) {
|
||||
// 若第一个用户任务为发起人,则自动完成任务
|
||||
List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
|
||||
if (CollUtil.isNotEmpty(tasks)) {
|
||||
String userIdStr = (String) variables.get(TaskConstants.PROCESS_INITIATOR);
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
for (Task task : tasks) {
|
||||
if (StrUtil.equals(task.getAssignee(), userIdStr)) {
|
||||
taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), LoginHelper.getNickName() + "发起流程申请");
|
||||
taskService.complete(task.getId(), variables);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 指派下一任务审批人
|
||||
* @param bpmnModel bpmn模型
|
||||
* @param processInsId 流程实例id
|
||||
* @param userIds 用户ids
|
||||
*/
|
||||
private void assignNextUsers(BpmnModel bpmnModel, String processInsId, String userIds) {
|
||||
// 获取所有节点信息
|
||||
List<Task> list = taskService.createTaskQuery()
|
||||
.processInstanceId(processInsId)
|
||||
.list();
|
||||
if (list.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Queue<String> assignIds = CollUtil.newLinkedList(userIds.split(","));
|
||||
if (list.size() == assignIds.size()) {
|
||||
for (Task task : list) {
|
||||
taskService.setAssignee(task.getId(), assignIds.poll());
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 优先处理非多实例任务
|
||||
Iterator<Task> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Task task = iterator.next();
|
||||
if (!ModelUtils.isMultiInstance(bpmnModel, task.getTaskDefinitionKey())) {
|
||||
if (!assignIds.isEmpty()) {
|
||||
taskService.setAssignee(task.getId(), assignIds.poll());
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
// 若存在多实例任务,则进行动态加减签
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
if (assignIds.isEmpty()) {
|
||||
// 动态减签
|
||||
for (Task task : list) {
|
||||
runtimeService.deleteMultiInstanceExecution(task.getExecutionId(), true);
|
||||
}
|
||||
} else {
|
||||
// 动态加签
|
||||
for (String assignId : assignIds) {
|
||||
Map<String, Object> assignVariables = Collections.singletonMap(BpmnXMLConstants.ATTRIBUTE_TASK_USER_ASSIGNEE, assignId);
|
||||
runtimeService.addMultiInstanceExecution(list.get(0).getTaskDefinitionKey(), list.get(0).getProcessInstanceId(), assignVariables);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?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.klp.workflow.mapper.WfCategoryMapper">
|
||||
|
||||
<resultMap type="com.klp.workflow.domain.WfCategory" id="FlowCategoryResult">
|
||||
<result property="categoryId" column="category_id"/>
|
||||
<result property="categoryName" column="category_name"/>
|
||||
<result property="code" column="code"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?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.klp.workflow.mapper.WfCopyMapper">
|
||||
|
||||
<resultMap type="com.klp.workflow.domain.WfCopy" id="WfCopyResult">
|
||||
<result property="copyId" column="copy_id"/>
|
||||
<result property="title" column="title"/>
|
||||
<result property="processId" column="process_id"/>
|
||||
<result property="processName" column="process_name"/>
|
||||
<result property="categoryId" column="category_id"/>
|
||||
<result property="taskId" column="taskId"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?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.klp.workflow.mapper.WfDeployFormMapper">
|
||||
|
||||
<resultMap type="com.klp.workflow.domain.WfDeployForm" id="WfDeployFormResult">
|
||||
<result property="deployId" column="deploy_id"/>
|
||||
<result property="formKey" column="form_key"/>
|
||||
<result property="nodeKey" column="node_key"/>
|
||||
<result property="nodeName" column="node_name"/>
|
||||
<result property="content" column="content"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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.klp.workflow.mapper.WfFormMapper">
|
||||
|
||||
<resultMap type="com.klp.workflow.domain.WfForm" id="WfFormResult">
|
||||
<result property="formId" column="form_id"/>
|
||||
<result property="formName" column="form_name"/>
|
||||
<result property="content" column="content"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectFormVoList" resultType="com.klp.workflow.domain.vo.WfFormVo">
|
||||
SELECT
|
||||
t1.form_id AS formId,
|
||||
t1.form_name AS formName,
|
||||
t1.content AS content
|
||||
FROM wf_form t1
|
||||
LEFT JOIN wf_deploy_form t2 ON t1.form_id = t2.form_id
|
||||
${ew.getCustomSqlSegment}
|
||||
</select>
|
||||
</mapper>
|
||||
8
pom.xml
8
pom.xml
@@ -321,13 +321,6 @@
|
||||
<version>${klp-flowable-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 工作流模块 -->
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-flowable</artifactId>
|
||||
<version>${klp-flowable-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- OSS对象存储模块 -->
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
@@ -411,7 +404,6 @@
|
||||
<module>klp-common</module>
|
||||
<module>klp-demo</module>
|
||||
<module>klp-extend</module>
|
||||
<module>klp-flowable</module>
|
||||
<module>klp-framework</module>
|
||||
<module>klp-generator</module>
|
||||
<module>klp-job</module>
|
||||
|
||||
Reference in New Issue
Block a user