From 3c8d864b5f68af5167199e0d5c9ff6c0c5852638 Mon Sep 17 00:00:00 2001 From: 疯狂的狮子Li <15040126243@163.com> Date: 星期一, 20 一月 2025 11:35:45 +0800 Subject: [PATCH] !639 发布 5.3.0-BETA 公测版本 Merge pull request !639 from 疯狂的狮子Li/dev --- ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 266 insertions(+), 0 deletions(-) diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java new file mode 100644 index 0000000..a881ba6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java @@ -0,0 +1,266 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.core.dto.DefJson; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.PublishStatus; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowSkip; +import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.warm.flow.orm.mapper.FlowSkipMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.dromara.common.core.constant.TenantConstants.DEFAULT_TENANT_ID; + +/** + * 娴佺▼瀹氫箟 鏈嶅姟灞傚疄鐜� + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwDefinitionServiceImpl implements IFlwDefinitionService { + + private final DefService defService; + private final FlowDefinitionMapper flowDefinitionMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowNodeMapper flowNodeMapper; + private final FlowSkipMapper flowSkipMapper; + private final FlwCategoryMapper flwCategoryMapper; + + /** + * 鏌ヨ娴佺▼瀹氫箟鍒楄〃 + * + * @param flowDefinition 娴佺▼瀹氫箟淇℃伅 + * @param pageQuery 鍒嗛〉 + * @return 杩斿洖鍒嗛〉鍒楄〃 + */ + @Override + public TableDataInfo<FlowDefinitionVo> queryList(FlowDefinition flowDefinition, PageQuery pageQuery) { + LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition); + wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey()); + Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + TableDataInfo<FlowDefinitionVo> build = TableDataInfo.build(); + build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class)); + build.setTotal(page.getTotal()); + return build; + } + + /** + * 鏌ヨ鏈彂甯冪殑娴佺▼瀹氫箟鍒楄〃 + * + * @param flowDefinition 娴佺▼瀹氫箟淇℃伅 + * @param pageQuery 鍒嗛〉 + * @return 杩斿洖鍒嗛〉鍒楄〃 + */ + @Override + public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) { + LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition); + wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey())); + Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + TableDataInfo<FlowDefinitionVo> build = TableDataInfo.build(); + build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class)); + build.setTotal(page.getTotal()); + return build; + } + + private LambdaQueryWrapper<FlowDefinition> buildQueryWrapper(FlowDefinition flowDefinition) { + LambdaQueryWrapper<FlowDefinition> wrapper = Wrappers.lambdaQuery(); + wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowCode()), FlowDefinition::getFlowCode, flowDefinition.getFlowCode()); + wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowName()), FlowDefinition::getFlowName, flowDefinition.getFlowName()); + if (StringUtils.isNotBlank(flowDefinition.getCategory())) { + List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinition.getCategory())); + wrapper.in(FlowDefinition::getCategory, categoryIds); + } + wrapper.orderByDesc(FlowDefinition::getCreateTime); + return wrapper; + } + + /** + * 鍙戝竷娴佺▼瀹氫箟 + * + * @param id 娴佺▼瀹氫箟id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean publish(Long id) { + List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, id)); + List<String> errorMsg = new ArrayList<>(); + if (CollUtil.isNotEmpty(flowNodes)) { + for (FlowNode flowNode : flowNodes) { + String applyNodeCode = WorkflowUtils.applyNodeCode(id); + if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) { + errorMsg.add(flowNode.getNodeName()); + } + } + if (CollUtil.isNotEmpty(errorMsg)) { + throw new ServiceException("鑺傜偣銆�" + StringUtils.join(errorMsg, ",") + "銆戞湭閰嶇疆鍔炵悊浜�!"); + } + } + return defService.publish(id); + } + + /** + * 瀵煎叆娴佺▼瀹氫箟 + * + * @param file 鏂囦欢 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean importJson(MultipartFile file, String category) { + try { + DefJson defJson = JsonUtils.parseObject(file.getBytes(), DefJson.class); + defJson.setCategory(category); + defService.importDef(defJson); + } catch (IOException e) { + log.error("璇诲彇鏂囦欢娴侀敊璇�: {}", e.getMessage(), e); + throw new IllegalStateException("鏂囦欢璇诲彇澶辫触锛岃妫�鏌ユ枃浠跺唴瀹�", e); + } + return true; + } + + /** + * 瀵煎嚭娴佺▼瀹氫箟 + * + * @param id 娴佺▼瀹氫箟id + * @param response 鍝嶅簲 + * @throws IOException 寮傚父 + */ + @Override + public void exportDef(Long id, HttpServletResponse response) throws IOException { + byte[] data = defService.exportJson(id).getBytes(StandardCharsets.UTF_8); + // 璁剧疆鍝嶅簲澶村拰鍐呭绫诲瀷 + response.reset(); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setContentType("application/text"); + response.setHeader("Content-Disposition", "attachment;"); + response.addHeader("Content-Length", "" + data.length); + IoUtil.write(response.getOutputStream(), false, data); + } + + /** + * 鍒犻櫎娴佺▼瀹氫箟 + * + * @param ids 娴佺▼瀹氫箟id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeDef(List<Long> ids) { + LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery(); + wrapper.in(FlowHisTask::getDefinitionId, ids); + List<FlowHisTask> flowHisTasks = flowHisTaskMapper.selectList(wrapper); + if (CollUtil.isNotEmpty(flowHisTasks)) { + List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId)); + if (CollUtil.isNotEmpty(flowDefinitions)) { + String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode); + log.error("娴佺▼瀹氫箟銆恵}銆戝凡琚娇鐢ㄤ笉鍙鍒犻櫎锛�", join); + throw new ServiceException("娴佺▼瀹氫箟銆�" + join + "銆戝凡琚娇鐢ㄤ笉鍙鍒犻櫎锛�"); + } + } + try { + defService.removeDef(ids); + } catch (Exception e) { + log.error("Error removing flow definitions: {}", e.getMessage(), e); + throw new RuntimeException("Failed to remove flow definitions", e); + } + return true; + } + + /** + * 鏂板绉熸埛娴佺▼瀹氫箟 + * + * @param tenantId 绉熸埛id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void syncDef(String tenantId) { + List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID)); + if (CollUtil.isEmpty(flowDefinitions)) { + return; + } + FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper<FlowCategory>() + .eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID)); + flowCategory.setCategoryId(null); + flowCategory.setTenantId(tenantId); + flwCategoryMapper.insert(flowCategory); + List<Long> defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId); + List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().in(FlowNode::getDefinitionId, defIds)); + List<FlowSkip> flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper<FlowSkip>().in(FlowSkip::getDefinitionId, defIds)); + for (FlowDefinition definition : flowDefinitions) { + FlowDefinition flowDefinition = BeanUtil.toBean(definition, FlowDefinition.class); + flowDefinition.setId(null); + flowDefinition.setTenantId(tenantId); + flowDefinition.setIsPublish(0); + flowDefinition.setCategory(String.valueOf(flowCategory.getCategoryId())); + int insert = flowDefinitionMapper.insert(flowDefinition); + if (insert <= 0) { + log.info("鍚屾娴佺▼瀹氫箟銆恵}銆戝け璐ワ紒", definition.getFlowCode()); + continue; + } + log.info("鍚屾娴佺▼瀹氫箟銆恵}銆戞垚鍔燂紒", definition.getFlowCode()); + Long definitionId = flowDefinition.getId(); + if (CollUtil.isNotEmpty(flowNodes)) { + List<FlowNode> nodes = StreamUtils.filter(flowNodes, node -> node.getDefinitionId().equals(definition.getId())); + if (CollUtil.isNotEmpty(nodes)) { + List<FlowNode> flowNodeList = BeanUtil.copyToList(nodes, FlowNode.class); + flowNodeList.forEach(e -> { + e.setId(null); + e.setDefinitionId(definitionId); + e.setTenantId(tenantId); + e.setPermissionFlag(null); + }); + flowNodeMapper.insertOrUpdate(flowNodeList); + } + } + if (CollUtil.isNotEmpty(flowSkips)) { + List<FlowSkip> skips = StreamUtils.filter(flowSkips, skip -> skip.getDefinitionId().equals(definition.getId())); + if (CollUtil.isNotEmpty(skips)) { + List<FlowSkip> flowSkipList = BeanUtil.copyToList(skips, FlowSkip.class); + flowSkipList.forEach(e -> { + e.setId(null); + e.setDefinitionId(definitionId); + e.setTenantId(tenantId); + }); + flowSkipMapper.insertOrUpdate(flowSkipList); + } + } + } + } +} -- Gitblit v1.9.3