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