diff --git a/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/constant/ProcessInstanceConstant.java b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/constant/ProcessInstanceConstant.java
index c64c3f40c..2ab6f372c 100644
--- a/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/constant/ProcessInstanceConstant.java
+++ b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/constant/ProcessInstanceConstant.java
@@ -50,6 +50,16 @@ public class ProcessInstanceConstant {
*/
public static final String USER_TASK_REFUSE_TYPE_TO_NODE = "TO_NODE";
+ /**
+ * 拒绝处理策略:驳回到发起人 审批人拒绝后,流程跳转回发起人节点,发起人可重新编辑提交
+ */
+ public static final String USER_TASK_REFUSE_TYPE_TO_START = "TO_START";
+
+ /**
+ * 流程变量:驳回到发起人标识 用于标记流程实例是否处于驳回待重新提交状态
+ */
+ public static final String REJECT_TO_STARTER_VAR = "rejectToStarter";
+
/**
* 多人审批模式:会签 所有审批人都必须同意才能通过,任何一人拒绝则不通过
*/
diff --git a/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/vo/ProcessInstanceRecordVo.java b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/vo/ProcessInstanceRecordVo.java
new file mode 100644
index 000000000..43b39975a
--- /dev/null
+++ b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/vo/ProcessInstanceRecordVo.java
@@ -0,0 +1,38 @@
+package com.pig4cloud.pigx.flow.vo;
+
+import com.pig4cloud.pigx.flow.entity.ProcessInstanceRecord;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 流程实例记录视图对象
+ *
+ * 继承自ProcessInstanceRecord实体类,用于扩展查询返回的额外信息。
+ * 包含流程实例的驳回状态等运行时信息。
+ *
+ *
+ * @author pigx
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProcessInstanceRecordVo extends ProcessInstanceRecord {
+
+ /**
+ * 是否驳回到发起人状态
+ *
+ * true表示流程已被驳回到发起人,等待发起人重新编辑提交;
+ * false或null表示流程正常运行中
+ *
+ */
+ private Boolean rejectToStarter;
+
+ /**
+ * 重新提交的任务ID
+ *
+ * 当rejectToStarter为true时,此字段保存发起人节点(root)的任务ID,
+ * 用于前端调用重新提交接口
+ *
+ */
+ private String resubmitTaskId;
+
+}
diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessTaskController.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessTaskController.java
index 62d5be7df..94f0116d7 100644
--- a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessTaskController.java
+++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessTaskController.java
@@ -159,4 +159,23 @@ public class ProcessTaskController {
return taskService.back(taskParamDto);
}
+ /**
+ * 重新提交任务(驳回到发起人后)
+ *
+ * 当流程被驳回到发起人后,发起人可使用此接口重新编辑表单并提交。
+ * 与completeTask不同:
+ * 1. 不需要填写审批意见
+ * 2. 会自动清理驳回标识
+ * 3. 提交后流程继续到下一个审批节点
+ *
+ * @param taskParamDto 重新提交参数,包含:
+ * - taskId: 发起人节点的任务ID
+ * - formData: 更新后的表单数据
+ * @return R 统一响应对象,操作成功返回提交结果
+ */
+ @PostMapping("resubmitTask")
+ public R resubmitTask(@RequestBody TaskParamDto taskParamDto) {
+ return taskService.resubmitTask(taskParamDto);
+ }
+
}
diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/ITaskService.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/ITaskService.java
index bff9632bd..b15de35a5 100644
--- a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/ITaskService.java
+++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/ITaskService.java
@@ -106,4 +106,18 @@ public interface ITaskService {
*/
R queryTaskData();
+ /**
+ * 重新提交任务(驳回到发起人后)
+ *
+ * 当流程被驳回到发起人时,发起人使用此方法重新编辑表单并提交。
+ * 与普通completeTask不同:
+ * 1. 不需要填写审批意见
+ * 2. 会清理 rejectToStarter 流程变量
+ * 3. 完成后流程继续到下一个审批节点
+ *
+ * @param taskParamDto 任务参数,包含taskId和更新后的formData
+ * @return 操作结果
+ */
+ R resubmitTask(TaskParamDto taskParamDto);
+
}
diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java
index 00fdd60e8..e3b09edd1 100644
--- a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java
+++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java
@@ -29,6 +29,7 @@ import com.pig4cloud.pigx.flow.support.utils.NodeUtil;
import com.pig4cloud.pigx.flow.vo.NodeFormatParamVo;
import com.pig4cloud.pigx.flow.vo.NodeVo;
import com.pig4cloud.pigx.flow.vo.ProcessCopyVo;
+import com.pig4cloud.pigx.flow.vo.ProcessInstanceRecordVo;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@@ -364,7 +365,39 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService {
Page instanceRecordPage = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getUserId, userId).eq(ProcessInstanceRecord::getStatus, taskQueryParamDto.getStatus()).between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessInstanceRecord::getCreateTime, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null).orderByDesc(ProcessInstanceRecord::getCreateTime).page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize()));
- return R.ok(instanceRecordPage);
+ // 转换为 VO 并添加驳回状态信息
+ List voList = BeanUtil.copyToList(instanceRecordPage.getRecords(), ProcessInstanceRecordVo.class);
+
+ for (ProcessInstanceRecordVo vo : voList) {
+ try {
+ // 从 Flowable 变量中获取 rejectToStarter 状态
+ Object rejectVar = runtimeService.getVariable(
+ vo.getProcessInstanceId(),
+ "rejectToStarter"
+ );
+ vo.setRejectToStarter(Boolean.TRUE.equals(rejectVar));
+
+ // 如果是驳回状态,获取 root 任务 ID 用于重新提交
+ if (Boolean.TRUE.equals(vo.getRejectToStarter())) {
+ Task task = taskService.createTaskQuery()
+ .processInstanceId(vo.getProcessInstanceId())
+ .taskDefinitionKey("root")
+ .singleResult();
+ if (task != null) {
+ vo.setResubmitTaskId(task.getId());
+ }
+ }
+ } catch (Exception e) {
+ // 流程可能已结束,设置为 false
+ vo.setRejectToStarter(false);
+ }
+ }
+
+ // 构建返回的分页对象
+ Page resultPage = new Page<>(instanceRecordPage.getCurrent(), instanceRecordPage.getSize(), instanceRecordPage.getTotal());
+ resultPage.setRecords(voList);
+
+ return R.ok(resultPage);
}
/**
diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java
index de2f5b541..daf3163fd 100644
--- a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java
+++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java
@@ -10,6 +10,7 @@ import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import com.pig4cloud.pigx.flow.constant.NodeStatusEnum;
+import com.pig4cloud.pigx.flow.constant.ProcessInstanceConstant;
import com.pig4cloud.pigx.flow.dto.IndexPageStatistics;
import com.pig4cloud.pigx.flow.dto.Node;
import com.pig4cloud.pigx.flow.dto.TaskParamDto;
@@ -483,6 +484,79 @@ public class TaskServiceImpl implements ITaskService {
return flowableEngineService.back(taskParamDto);
}
+ /**
+ * 重新提交任务(驳回到发起人后)
+ *
+ * 当流程被驳回到发起人时,发起人使用此方法重新编辑表单并提交。
+ * 该方法会:
+ * 1. 验证任务存在且属于当前用户
+ * 2. 验证任务是 root 节点任务
+ * 3. 更新表单数据
+ * 4. 清理 rejectToStarter 流程变量
+ * 5. 完成任务,流程继续到下一个审批节点
+ *
+ *
+ * @param taskParamDto 任务参数,包含taskId和更新后的formData
+ * @return R 操作结果
+ */
+ @Override
+ @SneakyThrows
+ @Transactional(rollbackFor = Exception.class)
+ public R resubmitTask(TaskParamDto taskParamDto) {
+ long userId = SecurityUtils.getUser().getId();
+
+ // 1. 获取任务并验证
+ Task task = taskService.createTaskQuery()
+ .taskId(taskParamDto.getTaskId())
+ .taskTenantId(TenantContextHolder.getTenantId().toString())
+ .taskAssignee(String.valueOf(userId))
+ .singleResult();
+
+ if (task == null) {
+ return R.failed("任务不存在或无权限操作");
+ }
+
+ // 2. 验证是 root 任务(发起人节点)
+ if (!StrUtil.equals(task.getTaskDefinitionKey(), "root")) {
+ return R.failed("非重新提交任务,无法操作");
+ }
+
+ String processInstanceId = task.getProcessInstanceId();
+
+ // 3. 更新表单数据
+ if (CollUtil.isNotEmpty(taskParamDto.getFormData())) {
+ runtimeService.setVariables(task.getExecutionId(), taskParamDto.getFormData());
+
+ // 同步更新到 ProcessInstanceRecord
+ ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery()
+ .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId)
+ .one();
+
+ if (processInstanceRecord != null) {
+ Map existingFormData = new HashMap<>();
+ if (StrUtil.isNotBlank(processInstanceRecord.getFormData())) {
+ existingFormData = objectMapper.readValue(processInstanceRecord.getFormData(),
+ new TypeReference