Selaa lähdekoodia

Merge remote-tracking branch 'origin/master-ai-cell' into CID-打电话

吴树波 3 viikkoa sitten
vanhempi
commit
b3d1c48cbd
31 muutettua tiedostoa jossa 495 lisäystä ja 58 poistoa
  1. 1 0
      fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallLogCallphone.java
  2. 4 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyAiWorkflowExecMapper.java
  3. 25 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticBusinessMapper.java
  4. 8 0
      fs-service/src/main/java/com/fs/company/service/CompanyWorkflowEngine.java
  5. 2 0
      fs-service/src/main/java/com/fs/company/service/IWorkflowNode.java
  6. 5 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogAddwxServiceImpl.java
  7. 4 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogCallphoneServiceImpl.java
  8. 4 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogSendmsgServiceImpl.java
  9. 19 6
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java
  10. 111 12
      fs-service/src/main/java/com/fs/company/service/impl/CompanyWorkflowEngineImpl.java
  11. 145 17
      fs-service/src/main/java/com/fs/company/service/impl/call/node/AbstractWorkflowNode.java
  12. 6 1
      fs-service/src/main/java/com/fs/company/service/impl/call/node/AiAddWxTaskNode.java
  13. 6 1
      fs-service/src/main/java/com/fs/company/service/impl/call/node/AiCallTaskNode.java
  14. 6 1
      fs-service/src/main/java/com/fs/company/service/impl/call/node/AiSendMsgTaskNode.java
  15. 5 0
      fs-service/src/main/java/com/fs/company/service/impl/call/node/ConditionNode.java
  16. 7 2
      fs-service/src/main/java/com/fs/company/service/impl/call/node/DelayNode.java
  17. 6 1
      fs-service/src/main/java/com/fs/company/service/impl/call/node/EndNode.java
  18. 6 1
      fs-service/src/main/java/com/fs/company/service/impl/call/node/OutBoundTaskNode.java
  19. 6 6
      fs-service/src/main/java/com/fs/company/service/impl/call/node/StartNode.java
  20. 13 4
      fs-service/src/main/java/com/fs/company/service/impl/call/node/WorkflowNodeFactory.java
  21. 1 1
      fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyAiWorkflowExecLogMapper.java
  22. 1 1
      fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyAiWorkflowExecMapper.java
  23. 13 0
      fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyVoiceRoboticBusinessMapper.java
  24. 1 1
      fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyWorkflowEdgeMapper.java
  25. 1 1
      fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyWorkflowNodeMapper.java
  26. 12 0
      fs-service/src/main/java/com/fs/company/service/nodeInterface/HasObjectMapper.java
  27. 1 1
      fs-service/src/main/java/com/fs/company/service/nodeInterface/HasRedisNode.java
  28. 6 0
      fs-service/src/main/java/com/fs/company/vo/ExecutionResult.java
  29. 21 0
      fs-service/src/main/resources/mapper/company/CompanyAiWorkflowExecMapper.xml
  30. 48 0
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticBusinessMapper.xml
  31. 1 1
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogCallphoneMapper.xml

+ 1 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallLogCallphone.java

@@ -3,6 +3,7 @@ package com.fs.company.domain;
 import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
+import java.util.UUID;
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;

+ 4 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyAiWorkflowExecMapper.java

@@ -44,6 +44,8 @@ public interface CompanyAiWorkflowExecMapper extends BaseMapper<CompanyAiWorkflo
      */
     int updateCompanyAiWorkflowExec(CompanyAiWorkflowExec companyAiWorkflowExec);
 
+    int updateByWorkflowInstanceId(CompanyAiWorkflowExec companyAiWorkflowExec);
+
     /**
      * 删除AI外呼工作流执行
      * 
@@ -66,4 +68,6 @@ public interface CompanyAiWorkflowExecMapper extends BaseMapper<CompanyAiWorkflo
      * @return
      */
     CompanyAiWorkflowExec selectByWorkflowInstanceId(@Param("workflowInstanceId") String workflowInstanceId);
+
+    CompanyAiWorkflowExec selectByWorkflowInstanceIdAndCurrentNode(@Param("workflowInstanceId") String workflowInstanceId, @Param("currentNode") String currentNode);
 }

+ 25 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticBusinessMapper.java

@@ -3,6 +3,9 @@ package com.fs.company.mapper;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.company.domain.CompanyVoiceRoboticBusiness;
+import io.lettuce.core.dynamic.annotation.Param;
+
+import javax.validation.constraints.NotNull;
 
 /**
  * ai外呼业务Mapper接口
@@ -58,4 +61,26 @@ public interface CompanyVoiceRoboticBusinessMapper extends BaseMapper<CompanyVoi
      * @return 结果
      */
     int deleteCompanyVoiceRoboticBusinessByIds(Long[] ids);
+
+    /**
+     * 批量插入业务数据
+     * @param businessList 业务数据列表
+     * @return 影响的行数
+     */
+    int insertBatch(@Param("list") List<CompanyVoiceRoboticBusiness> businessList);
+
+    /**
+     * 更新业务动作调用次数
+     * @param actionType 1、addWx; 2、callPhone; 3、sendMsg
+     * @param roboticId
+     * @param callerId
+     * @param wxClientId
+     * @return
+     */
+    int updateActionCount(@Param("actionType")@NotNull Integer actionType,
+                          @Param("roboticId") Long roboticId,
+                          @Param("callerId") Long callerId,
+                          @Param("wxClientId") Long wxClientId);
+
+    CompanyVoiceRoboticBusiness selectCompanyVoiceRoboticBusinessByWorkflowInstanceId(String workflowInstanceId);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/company/service/CompanyWorkflowEngine.java

@@ -46,4 +46,12 @@ public interface CompanyWorkflowEngine {
      * @param logEntry 日志记录
      */
     void logExecution(CompanyAiWorkflowExecLog logEntry);
+    /**
+     * 恢复工作流
+     * @param workflowInstanceId 工作流实例ID
+     * @param nodeKey 节点Key
+     * @param inputData 输入数据
+     * @return 恢复结果
+     */
+    ExecutionResult resumeFromBlockingNode(String workflowInstanceId, String nodeKey, Map<String, Object> inputData);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/company/service/IWorkflowNode.java

@@ -14,6 +14,8 @@ public interface IWorkflowNode {
     // 执行节点动作
     ExecutionResult execute(ExecutionContext context);
 
+    ExecutionResult continueExecute(ExecutionContext context);
+
     // 获取节点类型
     NodeTypeEnum getType();
 

+ 5 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogAddwxServiceImpl.java

@@ -6,6 +6,7 @@ import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.company.domain.CompanyVoiceRoboticCallLog;
 import com.fs.company.domain.CompanyWxClient;
+import com.fs.company.mapper.CompanyVoiceRoboticBusinessMapper;
 import com.fs.company.mapper.CompanyWxClientMapper;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogAddwxVO;
 import lombok.extern.slf4j.Slf4j;
@@ -26,6 +27,9 @@ import com.fs.company.service.ICompanyVoiceRoboticCallLogAddwxService;
 @Slf4j
 public class CompanyVoiceRoboticCallLogAddwxServiceImpl extends ServiceImpl<CompanyVoiceRoboticCallLogAddwxMapper, CompanyVoiceRoboticCallLogAddwx> implements ICompanyVoiceRoboticCallLogAddwxService {
 
+
+    @Autowired
+    CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper;
     /**
      * 查询调用日志_加微信
      * 
@@ -104,6 +108,7 @@ public class CompanyVoiceRoboticCallLogAddwxServiceImpl extends ServiceImpl<Comp
         try{
             companyVoiceRoboticCallLog.setCreateTime(DateUtils.getNowDate());
             baseMapper.insertCompanyVoiceRoboticCallLogAddwx(companyVoiceRoboticCallLog);
+            companyVoiceRoboticBusinessMapper.updateActionCount(1,companyVoiceRoboticCallLog.getRoboticId(),null,companyVoiceRoboticCallLog.getWxClientId());
         } catch (Exception e) {
             log.error("记录任务执行日志失败:失败数据:{}",companyVoiceRoboticCallLog, e);
         }

+ 4 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogCallphoneServiceImpl.java

@@ -19,6 +19,7 @@ import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.*;
+import com.fs.company.mapper.CompanyVoiceRoboticBusinessMapper;
 import com.fs.company.mapper.CompanyVoiceRoboticCalleesMapper;
 import com.fs.company.mapper.CompanyWxAccountMapper;
 import com.fs.company.vo.CidConfigVO;
@@ -52,6 +53,8 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
     CompanyWxAccountMapper companyWxAccountMapper;
     @Autowired
     CompanyVoiceRoboticCalleesMapper companyVoiceRoboticCalleesMapper;
+    @Autowired
+    CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper;
 
     /**
      * 查询调用日志_ai打电话
@@ -130,6 +133,7 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
         try {
             callPhoneLog.setCreateTime(DateUtils.getNowDate());
             baseMapper.insertCompanyVoiceRoboticCallLogCallphone(callPhoneLog);
+            companyVoiceRoboticBusinessMapper.updateActionCount(2,callPhoneLog.getRoboticId(),callPhoneLog.getCallerId(),null);
         } catch (Exception e) {
             log.error("记录任务执行日志失败:失败数据:{}", callPhoneLog, e);
         }

+ 4 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogSendmsgServiceImpl.java

@@ -5,6 +5,7 @@ import java.util.List;
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
+import com.fs.company.mapper.CompanyVoiceRoboticBusinessMapper;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogSendmsgVO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -24,6 +25,8 @@ import com.fs.company.service.ICompanyVoiceRoboticCallLogSendmsgService;
 @Slf4j
 public class CompanyVoiceRoboticCallLogSendmsgServiceImpl extends ServiceImpl<CompanyVoiceRoboticCallLogSendmsgMapper, CompanyVoiceRoboticCallLogSendmsg> implements ICompanyVoiceRoboticCallLogSendmsgService {
 
+    @Autowired
+    CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper;
     /**
      * 查询调用日志_发送短信
      * 
@@ -106,6 +109,7 @@ public class CompanyVoiceRoboticCallLogSendmsgServiceImpl extends ServiceImpl<Co
         try{
             sendMsgLog.setCreateTime(DateUtils.getNowDate());
             baseMapper.insertCompanyVoiceRoboticCallLogSendmsg(sendMsgLog);
+            companyVoiceRoboticBusinessMapper.updateActionCount(3,sendMsgLog.getRoboticId(),sendMsgLog.getCallerId(),null);
         } catch (Exception e) {
             log.error("记录任务执行日志失败:失败数据:{}",sendMsgLog, e);
         }

+ 19 - 6
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java

@@ -699,6 +699,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
     }
 
     @Override
+    @Transactional
     public void taskRun(Long id) {
         CompanyVoiceRobotic robotic = getById(id);
         robotic.setTaskStatus(1);
@@ -715,7 +716,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
      * 分配账号
      * @param robotic
      */
-    @Transactional
+//    @Transactional
     public List<CompanyWxClient> allocateWx(CompanyVoiceRobotic robotic) {
         List<CompanyWxClient> resArr = new ArrayList<>();
         //找到任务指定的微信用户
@@ -766,13 +767,25 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
 
     public void buildTaskBussiness(CompanyVoiceRobotic robotic){
         List<CompanyVoiceRoboticCallees> calleesList = companyVoiceRoboticCalleesMapper.selectByRoboticId(robotic.getId());
-        List<Long> userIds = calleesList.stream().map(e -> e.getUserId()).collect(Collectors.toList());
+        List<CompanyWxClient> companyWxClients = companyWxClientMapper.selectListByRoboticId(robotic.getId());
+        Map<String, CompanyWxClient> clientMp = companyWxClients.stream().collect(Collectors.toMap(e -> e.getRoboticId() + "-" + e.getCustomerId(), e -> e));
+        List<CompanyVoiceRoboticBusiness> addList = new ArrayList<>();
+        for (CompanyVoiceRoboticCallees callees : calleesList) {
+            CompanyVoiceRoboticBusiness companyVoiceRoboticBusiness = new CompanyVoiceRoboticBusiness();
+            companyVoiceRoboticBusiness.setRoboticId(robotic.getId());
+            companyVoiceRoboticBusiness.setCalleeId(callees.getId());
+            companyVoiceRoboticBusiness.setWxClientId(clientMp.getOrDefault(callees.getRoboticId() + "-" + callees.getUserId(),new CompanyWxClient()).getId());
+            companyVoiceRoboticBusiness.setAddWxDone(0);
+            companyVoiceRoboticBusiness.setCallPhoneDone(0);
+            companyVoiceRoboticBusiness.setSendMsgDone(0);
+            companyVoiceRoboticBusiness.setCreateTime(new Date());
+            addList.add(companyVoiceRoboticBusiness);
+        }
+        companyVoiceRoboticBusinessMapper.insertBatch(addList);
+    }
 
-        //todo lmx
-        CompanyVoiceRoboticBusiness companyVoiceRoboticBusiness = new CompanyVoiceRoboticBusiness();
-        companyVoiceRoboticBusiness.setRoboticId(robotic.getId());
+    private void taskJoin2Workflow(){
 
-        companyVoiceRoboticBusinessMapper.insert(companyVoiceRoboticBusiness);
     }
 
 

+ 111 - 12
fs-service/src/main/java/com/fs/company/service/impl/CompanyWorkflowEngineImpl.java

@@ -123,18 +123,34 @@ public class CompanyWorkflowEngineImpl implements CompanyWorkflowEngine {
             context.setCurrentNodeKey(nodeKey);
 
             if (node.isAsync()) {
-                // 执行节点逻辑 异步执行等待其他方式唤醒继续步骤
-                node.execute(context);
-                return null;
+                // 阻塞节点:执行节点后暂停流程,等待外部事件唤醒
+                ExecutionResult result = node.execute(context);
+
+//                // 记录执行日志
+//                logExecution(createLogEntry(workflowInstanceId, nodeKey, node.getType(), result));
+//
+//                // 如果执行失败,更新状态为失败
+//                if (!result.isSuccess()) {
+//                    updateWorkflowStatus(workflowInstanceId, ExecutionStatusEnum.FAILURE);
+//                    return result;
+//                }
+//
+//                // 阻塞节点执行成功后,将工作流状态设为暂停
+//                pauseWorkflowForBlockingNode(workflowInstanceId, nodeKey, context);
+
+                // 返回特殊结果表示流程被阻塞
+                return ExecutionResult.paused()
+                        .withNextNodeKey(result.getNextNodeKey())
+                        .withOutputData(result.getOutputData());
             } else {
                 // 执行节点
                 ExecutionResult result = node.execute(context);
 
                 // 记录执行日志
-                logExecution(createLogEntry(workflowInstanceId, nodeKey, node.getType(), result));
-
-                // 更新当前执行记录
-                updateCurrentExecution(workflowInstanceId, nodeKey, context);
+//                logExecution(createLogEntry(workflowInstanceId, nodeKey, node.getType(), result));
+//
+//                // 更新当前执行记录
+//                updateCurrentExecution(workflowInstanceId, nodeKey, context);
 
                 // 如果执行成功,返回下一个节点ID
                 if (result.isSuccess()) {
@@ -176,7 +192,7 @@ public class CompanyWorkflowEngineImpl implements CompanyWorkflowEngine {
             update.setStatus(ExecutionStatusEnum.PAUSED.getValue());
             update.setLastUpdateTime(LocalDateTime.now());
 
-            int rows = currentExecutionMapper.updateById(update);
+            int rows = currentExecutionMapper.updateByWorkflowInstanceId(update);
 
             if (rows > 0) {
                 log.info("工作流暂停成功: {}", workflowInstanceId);
@@ -206,7 +222,7 @@ public class CompanyWorkflowEngineImpl implements CompanyWorkflowEngine {
             update.setStatus(ExecutionStatusEnum.SUCCESS.getValue());
             update.setLastUpdateTime(LocalDateTime.now());
 
-            int rows = currentExecutionMapper.updateById(update);
+            int rows = currentExecutionMapper.updateByWorkflowInstanceId(update);
 
             if (rows > 0) {
                 log.info("工作流结束成功: {}", workflowInstanceId);
@@ -313,7 +329,7 @@ public class CompanyWorkflowEngineImpl implements CompanyWorkflowEngine {
             update.setVariables(objectMapper.writeValueAsString(context.getVariables()));
             update.setLastUpdateTime(LocalDateTime.now());
 
-            currentExecutionMapper.updateById(update);
+            currentExecutionMapper.updateByWorkflowInstanceId(update);
         } catch (JsonProcessingException e) {
             throw new RuntimeException(e);
         }
@@ -339,8 +355,7 @@ public class CompanyWorkflowEngineImpl implements CompanyWorkflowEngine {
         update.setWorkflowInstanceId(workflowInstanceId);
         update.setStatus(status.getValue());
         update.setLastUpdateTime(LocalDateTime.now());
-
-        currentExecutionMapper.updateById(update);
+        currentExecutionMapper.updateByWorkflowInstanceId(update);
     }
 
     /**
@@ -411,4 +426,88 @@ public class CompanyWorkflowEngineImpl implements CompanyWorkflowEngine {
         // 实现根据ID加载工作流定义的逻辑
         return companyWorkflowMapper.selectCompanyWorkflowById(id);
     }
+    /**
+     * 将工作流设置为阻塞状态
+     */
+    private void pauseWorkflowForBlockingNode(String workflowInstanceId, String nodeKey, ExecutionContext context) {
+        try {
+            CompanyAiWorkflowExec update = new CompanyAiWorkflowExec();
+            update.setWorkflowInstanceId(workflowInstanceId);
+            update.setStatus(ExecutionStatusEnum.WAITING.getValue());
+            update.setLastUpdateTime(LocalDateTime.now());
+            update.setVariables(objectMapper.writeValueAsString(context.getVariables()));
+
+            currentExecutionMapper.updateByWorkflowInstanceId(update);
+            log.info("工作流已阻塞在节点: {} -> {}", workflowInstanceId, nodeKey);
+        } catch (Exception e) {
+            log.error("更新工作流阻塞状态失败: {}", workflowInstanceId, e);
+        }
+    }
+    @Override
+    @Transactional
+    public ExecutionResult resumeFromBlockingNode(String workflowInstanceId, String nodeKey, Map<String, Object> inputData) {
+        try {
+            // 加载当前执行记录
+            CompanyAiWorkflowExec currentExec = currentExecutionMapper.selectByWorkflowInstanceIdAndCurrentNode(workflowInstanceId,nodeKey);
+
+            if (currentExec == null) {
+                return ExecutionResult.failure()
+                        .withErrorMessage("工作流实例不存在: " + workflowInstanceId);
+            }
+
+            // 检查当前工作流是否处于暂停状态
+            if (!Integer.valueOf(ExecutionStatusEnum.WAITING.getValue()).equals(currentExec.getStatus())) {
+                return ExecutionResult.failure()
+                        .withErrorMessage("工作流未处于暂停状态,无法唤醒: " + workflowInstanceId);
+            }
+
+            // 反序列化执行上下文并合并新的输入数据
+            ExecutionContext context = deserializeContext(currentExec);
+            if (inputData != null) {
+                context.getVariables().putAll(inputData);
+            }
+
+            // 加载工作流定义
+            CompanyWorkflow definition = loadCompanyWorkflow(currentExec.getWorkflowId());
+
+            // 创建节点实例
+            IWorkflowNode node = createNode(definition, nodeKey);
+            if (node == null) {
+                return ExecutionResult.failure()
+                        .withErrorMessage("节点不存在: " + nodeKey);
+            }
+
+            // 继续执行节点逻辑
+            ExecutionResult result = node.continueExecute(context);
+
+//            // 记录执行日志
+//            logExecution(createLogEntry(workflowInstanceId, nodeKey, node.getType(), result));
+//
+//            // 更新当前执行记录
+//            updateCurrentExecution(workflowInstanceId, nodeKey, context);
+//
+//            // 更新工作流状态为运行中
+//            updateWorkflowStatus(workflowInstanceId, ExecutionStatusEnum.RUNNING);
+
+            // 根据执行结果决定下一步操作
+            if (result.isSuccess()) {
+                if (StringUtils.isBlank(result.getNextNodeKey())) {
+                    // 如果没有下一个节点,完成工作流
+                    completeWorkflow(workflowInstanceId);
+                } else {
+                    // 执行下一个节点
+                    return executeNode(workflowInstanceId, result.getNextNodeKey());
+                }
+            } else {
+                // 执行失败,更新状态
+                updateWorkflowStatus(workflowInstanceId, ExecutionStatusEnum.FAILURE);
+            }
+            return result;
+        } catch (Exception e) {
+            log.error("唤醒阻塞节点失败: {} -> {}", workflowInstanceId, nodeKey, e);
+            updateWorkflowStatus(workflowInstanceId, ExecutionStatusEnum.FAILURE);
+            return ExecutionResult.failure()
+                    .withErrorMessage("Resume from blocking node failed: " + e.getMessage());
+        }
+    }
 }

+ 145 - 17
fs-service/src/main/java/com/fs/company/service/impl/call/node/AbstractWorkflowNode.java

@@ -1,17 +1,19 @@
 package com.fs.company.service.impl.call.node;
 
-import com.fs.company.domain.CompanyAiWorkflowExec;
-import com.fs.company.domain.CompanyWorkflowEdge;
-import com.fs.company.domain.CompanyWorkflowNode;
-import com.fs.company.mapper.CompanyAiWorkflowExecLogMapper;
-import com.fs.company.mapper.CompanyAiWorkflowExecMapper;
-import com.fs.company.mapper.CompanyWorkflowEdgeMapper;
-import com.fs.company.mapper.CompanyWorkflowNodeMapper;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.company.domain.*;
+import com.fs.company.mapper.*;
 import com.fs.company.param.ExecutionContext;
 import com.fs.company.service.*;
+import com.fs.company.service.nodeInterface.*;
 import com.fs.company.vo.ExecutionResult;
+import com.fs.enums.ExecutionStatusEnum;
+import com.fs.enums.NodeTypeEnum;
 import lombok.extern.slf4j.Slf4j;
+import net.bytebuddy.description.modifier.EnumerationState;
 
+import java.time.LocalDateTime;
 import java.util.*;
 
 /**
@@ -20,12 +22,17 @@ import java.util.*;
  * @description 工作节点基类
  */
 @Slf4j
-public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapper, IWorkflowNode, HasCompanyAiWorkflowExecMapper, HasCompanyWorkflowEdgeMapper, HasCompanyAiWorkflowExecLogMapper {
+//@SuppressWarnings("all")
+public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapper, IWorkflowNode,
+        HasCompanyAiWorkflowExecMapper, HasCompanyWorkflowEdgeMapper, HasCompanyAiWorkflowExecLogMapper, HasCompanyVoiceRoboticBusinessMapper,
+        HasObjectMapper {
 
     CompanyAiWorkflowExecMapper workflowExecMapper;
     CompanyWorkflowEdgeMapper companyWorkflowEdgeMapper;
     CompanyAiWorkflowExecLogMapper companyAiWorkflowExecLogMapper;
     CompanyWorkflowNodeMapper companyWorkflowNodeMapper;
+    CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper;
+    ObjectMapper objectMapper;
 
     @Override
     public void setCompanyWorkflowNodeMapper(CompanyWorkflowNodeMapper mapper) {
@@ -44,6 +51,14 @@ public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapp
     public void setCompanyAiWorkflowExecLogMapper(CompanyAiWorkflowExecLogMapper companyAiWorkflowExecLogMapper) {
         this.companyAiWorkflowExecLogMapper = companyAiWorkflowExecLogMapper;
     }
+    @Override
+    public void setCompanyVoiceRoboticBusinessMapper(CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper){
+        this.companyVoiceRoboticBusinessMapper = companyVoiceRoboticBusinessMapper;
+    }
+    @Override
+    public void setObjectMapper(ObjectMapper objectMapper){
+        this.objectMapper = objectMapper;
+    }
 
 
     protected String nodeKey;
@@ -60,13 +75,13 @@ public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapp
     public ExecutionResult execute(ExecutionContext context) {
         // 记录执行开始时间
         long startTime = System.currentTimeMillis();
-
+        ExecutionResult result = null;
         try {
             // 执行前的通用处理
             preExecute(context);
 
             // 执行具体的业务逻辑
-            ExecutionResult result = doExecute(context);
+            result = doExecute(context);
 
             // 记录执行时间
             long executionTime = System.currentTimeMillis() - startTime;
@@ -76,13 +91,24 @@ public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapp
         } catch (Exception e) {
             return handleExecutionError(e, context);
         } finally {
-            postExecute(context);
+            postExecute(context,result);
+        }
+    }
+    @Override
+    public ExecutionResult continueExecute(ExecutionContext context){
+        try{
+            CompanyAiWorkflowExec companyAiWorkflowExec = workflowExecMapper.selectByWorkflowInstanceId(context.getWorkflowInstanceId());
+            if(!Integer.valueOf(ExecutionStatusEnum.WAITING.getValue()).equals(companyAiWorkflowExec.getStatus())){
+                return handleExecutionError( new Exception("状态不符合"), context);
+            }
+            return doContinue(context);
+        } catch (Exception e) {
+            return handleExecutionError(e, context);
         }
     }
 
-    /**
-     * 子类必须实现的具体执行逻辑
-     */
+    protected abstract ExecutionResult doContinue(ExecutionContext context);
+
     protected abstract ExecutionResult doExecute(ExecutionContext context);
 
     /**
@@ -96,11 +122,16 @@ public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapp
     /**
      * 执行后的后处理
      */
-    protected void postExecute(ExecutionContext context) {
+    protected void postExecute(ExecutionContext context,ExecutionResult result) {
         long endTime = System.currentTimeMillis();
         context.setVariable("node_end_time_" + nodeKey, endTime);
         log.info("Completed execution of node: {} ({})", nodeKey, nodeName);
-        //todo 写入执行日志
+        //todo 写入执行日志等后置操作
+        if (result.isSuccess()) {
+
+        } else {
+            updateWorkflowStatus(context.getWorkflowInstanceId(), ExecutionStatusEnum.FAILURE);
+        }
     }
 
     /**
@@ -134,8 +165,14 @@ public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapp
 
         List<CompanyWorkflowEdge> companyWorkflowEdges =
                 companyWorkflowEdgeMapper.selectListByWorkflowIdAndNodeKey(companyAiWorkflowExec.getWorkflowId(), nodeKey);
-
         //todo 判定条件满足
+        if(null != companyWorkflowEdges && !companyWorkflowEdges.isEmpty()){
+            if(companyWorkflowEdges.size() > 1){
+
+            } else {
+                return companyWorkflowEdges.get(0).getTargetNodeKey();
+            }
+        }
 
         return companyWorkflowEdges.get(new Random().nextInt(companyWorkflowEdges.size())).getTargetNodeKey();
     }
@@ -152,4 +189,95 @@ public abstract class AbstractWorkflowNode implements HasCompanyWorkflowNodeMapp
         return companyWorkflowNode;
     }
 
+    public CompanyVoiceRoboticBusiness getRoboticBusiness(String workflowInstanceId){
+        CompanyVoiceRoboticBusiness companyVoiceRoboticBusiness = companyVoiceRoboticBusinessMapper.selectCompanyVoiceRoboticBusinessByWorkflowInstanceId(workflowInstanceId);
+        return companyVoiceRoboticBusiness;
+    }
+
+    /**
+     * 记录日志
+     * @param logEntry
+     */
+    public void logExecution(CompanyAiWorkflowExecLog logEntry) {
+        try {
+            CompanyAiWorkflowExecLog logRecord = new CompanyAiWorkflowExecLog();
+            logRecord.setWorkflowInstanceId(logEntry.getWorkflowInstanceId());
+            logRecord.setNodeId(logEntry.getNodeId());
+            logRecord.setNodeType(logEntry.getNodeType());
+            logRecord.setStatus(logEntry.getStatus());
+            logRecord.setInputData(objectMapper.writeValueAsString(logEntry.getInputData()));
+            logRecord.setOutputData(objectMapper.writeValueAsString(logEntry.getOutputData()));
+            logRecord.setStartTime(logEntry.getStartTime());
+            logRecord.setEndTime(logEntry.getEndTime());
+            logRecord.setErrorMessage(logEntry.getErrorMessage());
+            logRecord.setDuration(logEntry.getDuration());
+            companyAiWorkflowExecLogMapper.insert(logRecord);
+        } catch (Exception e) {
+            log.error("记录执行日志失败", e);
+        }
+    }
+
+    /**
+     * 创建执行日志
+     * @param workflowInstanceId
+     * @param nodeKey
+     * @param nodeType
+     * @param result
+     * @return
+     */
+    public CompanyAiWorkflowExecLog createLogEntry(String workflowInstanceId, String nodeKey,
+                                                              NodeTypeEnum nodeType, ExecutionResult result) {
+        try {
+            CompanyAiWorkflowExecLog logEntry = new CompanyAiWorkflowExecLog();
+            logEntry.setWorkflowInstanceId(workflowInstanceId);
+            logEntry.setNodeKey(nodeKey);
+            logEntry.setNodeType(nodeType.getValue());
+            logEntry.setStatus(result.getStatus().getValue());
+
+            logEntry.setOutputData(objectMapper.writeValueAsString(result.getOutputData()));
+            logEntry.setErrorMessage(result.getErrorMessage());
+            logEntry.setStartTime(new Date());
+            logEntry.setEndTime(new Date());
+            logEntry.setDuration(0L); // 可以根据实际情况计算持续时间
+
+            return logEntry;
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    /**
+     * 阻塞工作流
+     * @param workflowInstanceId
+     * @param nodeKey
+     * @param context
+     */
+    public void pauseWorkflowForBlockingNode(String workflowInstanceId, String nodeKey, ExecutionContext context) {
+        try {
+            CompanyAiWorkflowExec update = new CompanyAiWorkflowExec();
+            update.setWorkflowInstanceId(workflowInstanceId);
+            update.setStatus(ExecutionStatusEnum.WAITING.getValue());
+            update.setLastUpdateTime(LocalDateTime.now());
+            update.setVariables(objectMapper.writeValueAsString(context.getVariables()));
+            workflowExecMapper.updateByWorkflowInstanceId(update);
+            log.info("工作流已阻塞在节点: {} -> {}", workflowInstanceId, nodeKey);
+        } catch (Exception e) {
+            log.error("更新工作流阻塞状态失败: {}", workflowInstanceId, e);
+        }
+    }
+
+    /**
+     * 更新工作流状态
+     * @param workflowInstanceId
+     * @param status
+     */
+    public void updateWorkflowStatus(String workflowInstanceId, ExecutionStatusEnum status) {
+        CompanyAiWorkflowExec update = new CompanyAiWorkflowExec();
+        update.setWorkflowInstanceId(workflowInstanceId);
+        update.setStatus(status.getValue());
+        update.setLastUpdateTime(LocalDateTime.now());
+        workflowExecMapper.updateByWorkflowInstanceId(update);
+    }
+
 }

+ 6 - 1
fs-service/src/main/java/com/fs/company/service/impl/call/node/AiAddWxTaskNode.java

@@ -8,7 +8,7 @@ import com.fs.company.mapper.CompanyAiWorkflowExecMapper;
 import com.fs.company.mapper.CompanyWorkflowEdgeMapper;
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 import com.fs.company.param.ExecutionContext;
-import com.fs.company.service.HasCompanyWorkflowNodeMapper;
+import com.fs.company.service.nodeInterface.HasCompanyWorkflowNodeMapper;
 import com.fs.company.vo.ExecutionResult;
 import com.fs.enums.NodeTypeEnum;
 
@@ -51,6 +51,11 @@ public class AiAddWxTaskNode extends AbstractWorkflowNode implements HasCompanyW
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return null;
+    }
+
     @Override
     protected ExecutionResult doExecute(ExecutionContext context) {
         CompanyWorkflowNode node = companyWorkflowNodeMapper.selectById(context.getCurrentNodeId());

+ 6 - 1
fs-service/src/main/java/com/fs/company/service/impl/call/node/AiCallTaskNode.java

@@ -2,7 +2,7 @@ package com.fs.company.service.impl.call.node;
 
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 import com.fs.company.param.ExecutionContext;
-import com.fs.company.service.HasCompanyWorkflowNodeMapper;
+import com.fs.company.service.nodeInterface.HasCompanyWorkflowNodeMapper;
 import com.fs.company.vo.ExecutionResult;
 import com.fs.enums.NodeTypeEnum;
 
@@ -24,6 +24,11 @@ public class AiCallTaskNode extends AbstractWorkflowNode implements HasCompanyWo
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return null;
+    }
+
     @Override
     protected ExecutionResult doExecute(ExecutionContext context) {
 

+ 6 - 1
fs-service/src/main/java/com/fs/company/service/impl/call/node/AiSendMsgTaskNode.java

@@ -2,7 +2,7 @@ package com.fs.company.service.impl.call.node;
 
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 import com.fs.company.param.ExecutionContext;
-import com.fs.company.service.HasCompanyWorkflowNodeMapper;
+import com.fs.company.service.nodeInterface.HasCompanyWorkflowNodeMapper;
 import com.fs.company.vo.ExecutionResult;
 import com.fs.enums.NodeTypeEnum;
 
@@ -24,6 +24,11 @@ public class AiSendMsgTaskNode extends AbstractWorkflowNode implements HasCompan
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return null;
+    }
+
     @Override
     protected ExecutionResult doExecute(ExecutionContext context) {
 

+ 5 - 0
fs-service/src/main/java/com/fs/company/service/impl/call/node/ConditionNode.java

@@ -17,6 +17,11 @@ public class ConditionNode extends AbstractWorkflowNode {
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return null;
+    }
+
     @Override
     public ExecutionResult doExecute(ExecutionContext context) {
         return null;

+ 7 - 2
fs-service/src/main/java/com/fs/company/service/impl/call/node/DelayNode.java

@@ -3,8 +3,8 @@ package com.fs.company.service.impl.call.node;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 import com.fs.company.param.ExecutionContext;
-import com.fs.company.service.HasCompanyWorkflowNodeMapper;
-import com.fs.company.service.HasRedisNode;
+import com.fs.company.service.nodeInterface.HasCompanyWorkflowNodeMapper;
+import com.fs.company.service.nodeInterface.HasRedisNode;
 import com.fs.company.vo.ExecutionResult;
 import com.fs.enums.NodeTypeEnum;
 
@@ -32,6 +32,11 @@ public class DelayNode extends AbstractWorkflowNode implements HasRedisNode, Has
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return null;
+    }
+
     @Override
     protected ExecutionResult doExecute(ExecutionContext context) {
 

+ 6 - 1
fs-service/src/main/java/com/fs/company/service/impl/call/node/EndNode.java

@@ -2,7 +2,7 @@ package com.fs.company.service.impl.call.node;
 
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 import com.fs.company.param.ExecutionContext;
-import com.fs.company.service.HasCompanyWorkflowNodeMapper;
+import com.fs.company.service.nodeInterface.HasCompanyWorkflowNodeMapper;
 import com.fs.company.vo.ExecutionResult;
 import com.fs.enums.NodeTypeEnum;
 
@@ -23,6 +23,11 @@ public class EndNode extends AbstractWorkflowNode implements HasCompanyWorkflowN
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return null;
+    }
+
     @Override
     public ExecutionResult doExecute(ExecutionContext context) {
         return null;

+ 6 - 1
fs-service/src/main/java/com/fs/company/service/impl/call/node/OutBoundTaskNode.java

@@ -2,7 +2,7 @@ package com.fs.company.service.impl.call.node;
 
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 import com.fs.company.param.ExecutionContext;
-import com.fs.company.service.HasCompanyWorkflowNodeMapper;
+import com.fs.company.service.nodeInterface.HasCompanyWorkflowNodeMapper;
 import com.fs.company.vo.ExecutionResult;
 import com.fs.enums.NodeTypeEnum;
 
@@ -23,6 +23,11 @@ public class OutBoundTaskNode extends AbstractWorkflowNode implements HasCompany
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return null;
+    }
+
     @Override
     public ExecutionResult doExecute(ExecutionContext context) {
         return null;

+ 6 - 6
fs-service/src/main/java/com/fs/company/service/impl/call/node/StartNode.java

@@ -2,7 +2,7 @@ package com.fs.company.service.impl.call.node;
 
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 import com.fs.company.param.ExecutionContext;
-import com.fs.company.service.HasCompanyWorkflowNodeMapper;
+import com.fs.company.service.nodeInterface.HasCompanyWorkflowNodeMapper;
 import com.fs.company.vo.ExecutionResult;
 import com.fs.enums.NodeTypeEnum;
 
@@ -25,6 +25,11 @@ public class StartNode extends AbstractWorkflowNode implements HasCompanyWorkflo
         super(nodeKey, nodeName, properties);
     }
 
+    @Override
+    protected ExecutionResult doContinue(ExecutionContext context) {
+        return ExecutionResult.success();
+    }
+
     @Override
     public ExecutionResult doExecute(ExecutionContext context) {
         return ExecutionResult.success()
@@ -36,11 +41,6 @@ public class StartNode extends AbstractWorkflowNode implements HasCompanyWorkflo
         return NodeTypeEnum.START;
     }
 
-    @Override
-    protected void preExecute(ExecutionContext context){
-        super.preExecute(context);
-    }
-
     @Override
     public Boolean isAsync() {
         return false;

+ 13 - 4
fs-service/src/main/java/com/fs/company/service/impl/call/node/WorkflowNodeFactory.java

@@ -1,11 +1,10 @@
 package com.fs.company.service.impl.call.node;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fs.common.core.redis.RedisCache;
-import com.fs.company.mapper.CompanyAiWorkflowExecLogMapper;
-import com.fs.company.mapper.CompanyAiWorkflowExecMapper;
-import com.fs.company.mapper.CompanyWorkflowEdgeMapper;
-import com.fs.company.mapper.CompanyWorkflowNodeMapper;
+import com.fs.company.mapper.*;
 import com.fs.company.service.*;
+import com.fs.company.service.nodeInterface.*;
 import com.fs.enums.NodeTypeEnum;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -30,6 +29,10 @@ public class WorkflowNodeFactory implements IWorkflowNodeFactory {
     private CompanyWorkflowEdgeMapper companyWorkflowEdgeMapper;
     @Autowired
     private CompanyAiWorkflowExecLogMapper companyAiWorkflowExecLogMapper;
+    @Autowired
+    private CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper;
+    @Autowired
+    private ObjectMapper objectMapper;
 
     @Override
     public IWorkflowNode createNode(String nodeKey, NodeTypeEnum type, String nodeName,
@@ -87,6 +90,12 @@ public class WorkflowNodeFactory implements IWorkflowNodeFactory {
         if(node instanceof HasCompanyAiWorkflowExecLogMapper){
             ((HasCompanyAiWorkflowExecLogMapper) node).setCompanyAiWorkflowExecLogMapper(companyAiWorkflowExecLogMapper);
         }
+        if(node instanceof HasCompanyVoiceRoboticBusinessMapper){
+            ((HasCompanyVoiceRoboticBusinessMapper) node).setCompanyVoiceRoboticBusinessMapper(companyVoiceRoboticBusinessMapper);
+        }
+        if(node instanceof HasObjectMapper){
+            ((HasObjectMapper) node).setObjectMapper(objectMapper);
+        }
 
     }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/company/service/HasCompanyAiWorkflowExecLogMapper.java → fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyAiWorkflowExecLogMapper.java

@@ -1,4 +1,4 @@
-package com.fs.company.service;
+package com.fs.company.service.nodeInterface;
 
 
 import com.fs.company.mapper.CompanyAiWorkflowExecLogMapper;

+ 1 - 1
fs-service/src/main/java/com/fs/company/service/HasCompanyAiWorkflowExecMapper.java → fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyAiWorkflowExecMapper.java

@@ -1,4 +1,4 @@
-package com.fs.company.service;
+package com.fs.company.service.nodeInterface;
 
 import com.fs.company.mapper.CompanyAiWorkflowExecMapper;
 

+ 13 - 0
fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyVoiceRoboticBusinessMapper.java

@@ -0,0 +1,13 @@
+package com.fs.company.service.nodeInterface;
+
+import com.fs.company.mapper.CompanyVoiceRoboticBusinessMapper;
+
+/**
+ * @author MixLiu
+ * @date 2026/2/2 14:37
+ * @description
+ */
+public interface HasCompanyVoiceRoboticBusinessMapper {
+
+    void setCompanyVoiceRoboticBusinessMapper(CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper);
+}

+ 1 - 1
fs-service/src/main/java/com/fs/company/service/HasCompanyWorkflowEdgeMapper.java → fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyWorkflowEdgeMapper.java

@@ -1,4 +1,4 @@
-package com.fs.company.service;
+package com.fs.company.service.nodeInterface;
 
 import com.fs.company.mapper.CompanyWorkflowEdgeMapper;
 

+ 1 - 1
fs-service/src/main/java/com/fs/company/service/HasCompanyWorkflowNodeMapper.java → fs-service/src/main/java/com/fs/company/service/nodeInterface/HasCompanyWorkflowNodeMapper.java

@@ -1,4 +1,4 @@
-package com.fs.company.service;
+package com.fs.company.service.nodeInterface;
 
 import com.fs.company.mapper.CompanyWorkflowNodeMapper;
 

+ 12 - 0
fs-service/src/main/java/com/fs/company/service/nodeInterface/HasObjectMapper.java

@@ -0,0 +1,12 @@
+package com.fs.company.service.nodeInterface;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * @author MixLiu
+ * @date 2026/2/2 16:29
+ * @description
+ */
+public interface HasObjectMapper {
+    void setObjectMapper(ObjectMapper objectMapper);
+}

+ 1 - 1
fs-service/src/main/java/com/fs/company/service/HasRedisNode.java → fs-service/src/main/java/com/fs/company/service/nodeInterface/HasRedisNode.java

@@ -1,4 +1,4 @@
-package com.fs.company.service;
+package com.fs.company.service.nodeInterface;
 
 import com.fs.common.core.redis.RedisCache;
 

+ 6 - 0
fs-service/src/main/java/com/fs/company/vo/ExecutionResult.java

@@ -28,6 +28,12 @@ public class ExecutionResult {
         result.status = ExecutionStatusEnum.FAILURE;
         return result;
     }
+    public static ExecutionResult paused(){
+        ExecutionResult result = new ExecutionResult();
+        result.success = true;
+        result.status = ExecutionStatusEnum.WAITING;
+        return result;
+    }
 
     public ExecutionResult withNextNodeKey(String nextNodeKey) {
         this.nextNodeKey = nextNodeKey;

+ 21 - 0
fs-service/src/main/resources/mapper/company/CompanyAiWorkflowExecMapper.xml

@@ -95,6 +95,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where id = #{id}
     </update>
 
+    <update id="updateByWorkflowInstanceId"  parameterType="CompanyAiWorkflowExec" >
+        update company_ai_workflow_exec
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="workflowId != null">workflow_id = #{workflowId},</if>
+            <if test="workflowVersion != null">workflow_version = #{workflowVersion},</if>
+            <if test="currentNodeId != null">current_node_id = #{currentNodeId},</if>
+            <if test="currentNodeName != null">current_node_name = #{currentNodeName},</if>
+            <if test="currentNodeType != null">current_node_type = #{currentNodeType},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="variables != null">variables = #{variables},</if>
+            <if test="startTime != null">start_time = #{startTime},</if>
+            <if test="lastUpdateTime != null">last_update_time = #{lastUpdateTime},</if>
+            <if test="businessKey != null">business_key = #{businessKey},</if>
+        </trim>
+        where workflow_instance_id = #{workflowInstanceId}
+    </update>
+
     <delete id="deleteCompanyAiWorkflowExecById" parameterType="Long">
         delete from company_ai_workflow_exec where id = #{id}
     </delete>
@@ -108,4 +125,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectByWorkflowInstanceId" resultType="CompanyAiWorkflowExec">
         select * from company_ai_workflow_exec where workflow_instance_id = #{workflowInstanceId}
     </select>
+
+    <select id="selectByWorkflowInstanceIdAndCurrentNode" resultType="CompanyAiWorkflowExec">
+        select * from company_ai_workflow_exec where workflow_instance_id = #{workflowInstanceId} and current_node_key = #{currentNode}
+    </select>
 </mapper>

+ 48 - 0
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticBusinessMapper.xml

@@ -86,4 +86,52 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{id}
         </foreach>
     </delete>
+
+    <insert id="insertBatch" parameterType="java.util.List">
+        INSERT INTO company_voice_robotic_business
+        (robotic_id, callee_id, wx_client_id, add_wx_done, call_phone_done, send_msg_done, create_time, update_time)
+        VALUES
+        <foreach collection="list" item="item" index="index" separator=",">
+            (
+            #{item.roboticId},
+            #{item.calleeId},
+            #{item.wxClientId},
+            #{item.addWxDone},
+            #{item.callPhoneDone},
+            #{item.sendMsgDone},
+            #{item.createTime},
+            #{item.updateTime}
+            )
+        </foreach>
+    </insert>
+
+    <update id="updateActionCount" >
+        update company_voice_robotic_business
+        <if test="actionType == 1">
+            set add_wx_done = add_wx_done + 1
+        </if>
+        <if test="actionType == 2">
+            set call_phone_done = call_phone_done + 1
+        </if>
+        <if test="actionType == 3">
+            set send_msg_done = send_msg_done + 1
+        </if>
+        where
+            robotic_id = #{roboticId}
+        <if test="callerId != null">
+            and caller_id = #{callerId}
+        </if>
+
+        <if test="wxClientId != null">
+            and wx_client_id = #{wxClientId}
+        </if>
+    </update>
+
+    <select id="selectCompanyVoiceRoboticBusinessByWorkflowInstanceId" resultType="CompanyVoiceRoboticBusiness">
+        select
+            t2.*
+        from company_ai_workflow_exec t1
+                 INNER JOIN company_voice_robotic_business t2 on t1.business_key = t2.id
+        where t1.workflow_instance_id = #{workflowInstanceId}
+    </select>
 </mapper>

+ 1 - 1
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogCallphoneMapper.xml

@@ -147,7 +147,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select * from company_voice_robotic_call_log_callphone where robotic_id = #{roboticId} And caller_id = #{id} And status = 1
     </select>
     <select id="selectLogByRoboticIdAndCallerId"   resultType="CompanyVoiceRoboticCallLogCallphone">
-        select * from company_voice_robotic_call_log_callphone where robotic_id = #{roboticId} And caller_id = #{callerId}
+        select * from company_voice_robotic_call_log_callphone where robotic_id = #{roboticId} And caller_id = #{callerId} order by run_time asc limit 1
     </select>
 
     <select id="selectCompanyVoiceRoboticCallLogCallphoneListData" parameterType="com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone"  resultType="CompanyVoiceRoboticCallLogCallphone">