¶Ô±ÈÐÂÎļþ |
| | |
| | | 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, StreamUtils.toList(categoryIds, Convert::toStr)); |
| | | } |
| | | wrapper.orderByDesc(FlowDefinition::getCreateTime); |
| | | return wrapper; |
| | | } |
| | | |
| | | /** |
| | | * å叿µç¨å®ä¹ |
| | | * |
| | | * @param id æµç¨å®ä¹id |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public boolean publish(Long id) { |
| | | List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, id)); |
| | | List<String> errorMsg = new ArrayList<>(); |
| | | if (CollUtil.isNotEmpty(flowNodes)) { |
| | | for (FlowNode flowNode : flowNodes) { |
| | | String applyNodeCode = 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); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |